////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016-2018 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  camxsensornode.cpp
/// @brief SensorNode class implementation
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "camxcsiphysubmodule.h"
#include "camxhwcontext.h"
#include "camxpdlibraryhandler.h"
#include "camxpipeline.h"
#include "camxsensorpickmode.h"
#include "camxtrace.h"
#include "camxvendortags.h"
#include "chi.h"
#include "chipdlibinterface.h"
#include "camxpdafconfig.h"
#include "camxpdafdata.h"
#include "camxsensornode.h"
#include "camxtuningdatamanager.h"
#include "camximagesensorutils.h"

CAMX_NAMESPACE_BEGIN

/// @todo (CAMX-555) Adjust below constants
static const UINT SensorMaxCmdBufferManagerCount = 40;                       ///< Number of max command buffer managers
static const UINT InitialConfigCmdCount          = 1;                        ///< Number of command buffers in config command
static const UINT I2CInfoCmdCount                = 1;                        ///< Number of command buffers in I2C command

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorSubDevicesCache::SensorSubDevicesCache
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SensorSubDevicesCache::SensorSubDevicesCache()
{
    m_pCacheLock = Mutex::Create("SubDeviceCache");
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorSubDevicesCache::~SensorSubDevicesCache
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SensorSubDevicesCache::~SensorSubDevicesCache()
{
    m_pCacheLock->Destroy();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorSubDevicesCache::IncrementRefCount
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID SensorSubDevicesCache::IncrementRefCount(
    UINT32 cameraId)
{
    m_pCacheLock->Lock();

    if (m_refCount[cameraId] < MaxNumImageSensors)
    {
        m_refCount[cameraId]++;
    }
    CAMX_ASSERT(m_refCount[cameraId] <= MaxNumImageSensors);

    m_pCacheLock->Unlock();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorSubDevicesCache::ClearCache
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void SensorSubDevicesCache::ClearCache(
    UINT32 cameraId)
{
    m_pCacheLock->Lock();
    Utils::Memset(&m_sensorSubDevices[cameraId], 0, sizeof(SensorSubDeviceHandles));
    m_refCount[cameraId] = 0;
    m_bReleasehandle[cameraId] = FALSE;
    m_pCacheLock->Unlock();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorSubDevicesCache::CheckReleaseCond
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID SensorSubDevicesCache::CheckReleaseCond(
    UINT32 cameraId,
    UINT closeStatus)
{
    m_pCacheLock->Lock();

    // Reset the flag for checking release condition
    m_bReleasehandle[cameraId] = FALSE;

    if (m_refCount[cameraId] > 0)
    {
        m_refCount[cameraId]--;
    }
    CAMX_ASSERT(m_refCount[cameraId] >= 0);

    if (0 == m_refCount[cameraId] && TRUE == closeStatus)
    {
        m_bReleasehandle[cameraId] = TRUE;
    }
    m_pCacheLock->Unlock();
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorSubDevicesCache::SetSubDeviceHandle
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorSubDevicesCache::SetSubDeviceHandle(
    UINT32 cameraId,
    CSLDeviceHandle handle,
    SubDevice type)
{
    CamxResult result = CamxResultSuccess;

    if (cameraId >= MaxNumImageSensors)
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "cameraId: %d is beyond Max number of sensor", cameraId);
        result = CamxResultEFailed;
    }

    m_pCacheLock->Lock();

    switch (type)
    {
        case SensorHandle:
            m_sensorSubDevices[cameraId].sensorDevice.hDevice      = handle;
            m_sensorSubDevices[cameraId].sensorDevice.isAcquired   = TRUE;
            m_refCount[cameraId]++;
            break;
        case CSIPHYHandle:
            m_sensorSubDevices[cameraId].CSIPHYDevice.hDevice      = handle;
            m_sensorSubDevices[cameraId].CSIPHYDevice.isAcquired   = TRUE;
            break;
        case OISHandle:
            m_sensorSubDevices[cameraId].oisDevice.hDevice         = handle;
            m_sensorSubDevices[cameraId].oisDevice.isAcquired      = TRUE;
            break;
        case ActuatorHandle:
            m_sensorSubDevices[cameraId].actuatorDevice.hDevice    = handle;
            m_sensorSubDevices[cameraId].actuatorDevice.isAcquired = TRUE;
            break;
        case FlashHandle:
            m_sensorSubDevices[cameraId].flashDevice.hDevice       = handle;
            m_sensorSubDevices[cameraId].flashDevice.isAcquired    = TRUE;
            break;
        default:
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Invalid subdevice type: %d", type);
            result = CamxResultEFailed;
            break;
    }

    m_pCacheLock->Unlock();

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorSubDevicesCache::SetSubDeviceIndex
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorSubDevicesCache::SetSubDeviceIndex(
    UINT32 cameraId,
    INT32 deviceIndex,
    SubDevice type)
{
    CamxResult result = CamxResultSuccess;

    if (cameraId >= MaxNumImageSensors)
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "cameraId: %d is beyond Max number of sensor", cameraId);
        result = CamxResultEFailed;
    }
    m_pCacheLock->Lock();

    switch (type)
    {
        case SensorHandle:
            m_sensorSubDevices[cameraId].sensorDevice.deviceIndex   = deviceIndex;
            break;
        case CSIPHYHandle:
            m_sensorSubDevices[cameraId].CSIPHYDevice.deviceIndex   = deviceIndex;
            break;
        case OISHandle:
            m_sensorSubDevices[cameraId].oisDevice.deviceIndex      = deviceIndex;
            break;
        case ActuatorHandle:
            m_sensorSubDevices[cameraId].actuatorDevice.deviceIndex = deviceIndex;
            break;
        case FlashHandle:
            m_sensorSubDevices[cameraId].flashDevice.deviceIndex    = deviceIndex;
            break;
        default:
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Invalid subdevice type: %d", type);
            result = CamxResultEFailed;
            break;
    }

    m_pCacheLock->Unlock();

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorSubDevicesCache::SetSubDeviceData
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorSubDevicesCache::SetSubDeviceData(
    UINT32    cameraId,
    UINT32    data,
    SubDevice type)
{
    CamxResult result = CamxResultSuccess;
    if (cameraId >= MaxNumImageSensors)
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "cameraId: %d is beyond Max number of sensor %d", cameraId, MaxNumImageSensors);
        result = CamxResultEFailed;
    }

    m_pCacheLock->Lock();

    switch (type)
    {
        case SensorHandle:
            m_sensorSubDevices[cameraId].sensorDevice.dataMask   = data;
            break;
        case CSIPHYHandle:
            m_sensorSubDevices[cameraId].CSIPHYDevice.dataMask   = data;
            break;
        case OISHandle:
            m_sensorSubDevices[cameraId].oisDevice.dataMask      = data;
            break;
        case ActuatorHandle:
            m_sensorSubDevices[cameraId].actuatorDevice.dataMask = data;
            break;
        case FlashHandle:
            m_sensorSubDevices[cameraId].flashDevice.dataMask    = data;
            break;
        default:
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Invalid subdevice type: %d", type);
            result = CamxResultEFailed;
            break;
    }

    m_pCacheLock->Unlock();
    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorSubDevicesCache::GetSubDevice
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SubDeviceProperty SensorSubDevicesCache::GetSubDevice(
    UINT32 cameraId,
    SubDevice type
    ) const
{
    CAMX_ASSERT(cameraId < MaxNumImageSensors);

    m_pCacheLock->Lock();
    SubDeviceProperty subDeviceProperty;
    switch(type)
    {
        case SensorHandle:
            subDeviceProperty =  m_sensorSubDevices[cameraId].sensorDevice;
            break;
        case CSIPHYHandle:
            subDeviceProperty =  m_sensorSubDevices[cameraId].CSIPHYDevice;
            break;
        case OISHandle:
            subDeviceProperty =  m_sensorSubDevices[cameraId].oisDevice;
            break;
        case ActuatorHandle:
            subDeviceProperty =  m_sensorSubDevices[cameraId].actuatorDevice;
            break;
        case FlashHandle:
            subDeviceProperty =  m_sensorSubDevices[cameraId].flashDevice;
            break;
        default:
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Invalid subdevice type: %d returning sensor device handle by default",
                                                type);
            subDeviceProperty =  m_sensorSubDevices[cameraId].sensorDevice;
            break;
    }

    m_pCacheLock->Unlock();

    return subDeviceProperty;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::SensorNode
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SensorNode::SensorNode()
    : m_hSensorDevice(CSLInvalidHandle)
    , m_currentResolutionIndex(1)
    , m_currentSyncMode(NoSync)
    , m_hJobFamilyHandle(InvalidJobHandle)
    , m_sensorConfigStatus(SensorConfigurationStatus::SensorConfigurationStateUninitialized)
    , m_hJobFamilySubModuleOISHandle(InvalidJobHandle)
    , m_OISConfigStatus(SensorOISConfigurationStatus::SensorOISConfigurationStateUninitialized)
    , m_initialConfigPending(TRUE)
    , m_isMultiCameraUsecase(FALSE)
    , m_isMasterCamera(TRUE)
    , m_isPdafUpdated(FALSE)
{
    m_pNodeName              = "Sensor";
    m_derivedNodeHandlesMetaDone = TRUE;
    m_pSensorSubDevicesCache = SensorSubDevicesCache::GetInstance();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::~SensorNode
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SensorNode::~SensorNode()
{
    // Unregister job family first, we depend on the members we will be destroying to handle callbacks.
    if (InvalidJobHandle != m_hJobFamilyHandle)
    {
        const CHAR* pSensorName = m_pSensorModuleData->GetSensorDataObject()->GetSensorName();
        m_pThreadManager->UnregisterJobFamily(SensorThreadJobCallback, pSensorName, m_hJobFamilyHandle);
        m_hJobFamilyHandle = InvalidJobHandle;
    }

    // Unregister job family first, we depend on the members we will be destroying to handle callbacks.
    if (InvalidJobHandle != m_hJobFamilySubModuleOISHandle)
    {
        CHAR OISJobName[256];
        OsUtils::SNPrintF(OISJobName, sizeof(OISJobName), "%s_%s",
            m_pSensorModuleData->GetSensorDataObject()->GetSensorName(), "OIS");

        m_pThreadManager->UnregisterJobFamily(SensorThreadJobCallback, OISJobName, m_hJobFamilySubModuleOISHandle);
        m_hJobFamilySubModuleOISHandle = InvalidJobHandle;
    }

    UINT cameraCloseStatus = GetStaticSettings()->overrideCameraClose;

    m_pSensorSubDevicesCache->CheckReleaseCond(m_cameraId, cameraCloseStatus);

    // These resources are managed manually, hence recycled manually.
    if ((NULL != m_pConfigPacketManager) && (NULL != m_pConfigPacket))
    {
        m_pConfigPacketManager->Recycle(m_pConfigPacket);
        m_pConfigPacket = NULL;
    }

    if ((NULL != m_pConfigCmdBufferManager) && (NULL != m_pConfigCmdBuffer))
    {
        m_pConfigCmdBufferManager->Recycle(m_pConfigCmdBuffer);
        m_pConfigCmdBuffer = NULL;
    }

    if (NULL != m_pExposureInfo)
    {
        CAMX_FREE(m_pExposureInfo);
        m_pExposureInfo = NULL;
    }

    if (NULL != m_pRegSettings)
    {
        CAMX_FREE(m_pRegSettings);
        m_pRegSettings = NULL;
    }

    if (NULL != m_pPDAFSettings)
    {
        CAMX_FREE(m_pPDAFSettings);
        m_pPDAFSettings = NULL;
    }

    if (NULL != m_pExposureRegAddressInfo)
    {
        CAMX_FREE(m_pExposureRegAddressInfo);
        m_pExposureRegAddressInfo = NULL;
    }

    // Free all sub modules
    if (NULL != m_pActuator)
    {
        m_pActuator->Destroy();
        m_pActuator = NULL;
    }

    if (NULL != m_pOis)
    {
        m_pOis->Destroy();
        m_pOis = NULL;
    }

    if (NULL != m_pCSIPHY)
    {
        m_pCSIPHY->Destroy();
        m_pCSIPHY = NULL;
    }

    if (NULL != m_pFlash)
    {
        m_pFlash->Destroy();
        m_pFlash = NULL;
    }

    const StaticSettings* pStaticSettings = GetStaticSettings();
    CAMX_ASSERT(pStaticSettings != NULL);

    // Until a close camera call is made, sensor device handle is not released
    if (((NULL != m_pHwContext) && (TRUE == IsDeviceAcquired())) &&
        ((TRUE == m_pSensorSubDevicesCache->CanRelease(m_cameraId))||
         (FALSE == pStaticSettings->enableSensorCaching)))
    {
        CAMX_LOG_INFO(CamxLogGroupSensor,
                      "Releasing sensor device handle: %p for cameraId: %d, SensorCaching: %d, closeStatus: %d",
                      m_hSensorDevice,
                      m_cameraId,
                      pStaticSettings->enableSensorCaching,
                      cameraCloseStatus);
        CamxResult result = CSLReleaseDevice(m_pHwContext->GetCSLSession(), m_hSensorDevice);

        if (CamxResultSuccess == result)
        {
            SetDeviceAcquired(FALSE);
            CAMX_LOG_INFO(CamxLogGroupSensor, "ReleaseDevice on Sensor successful!");
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "ReleaseDevice on Sensor failed!");
        }

        m_pSensorSubDevicesCache->ClearCache(m_cameraId);
    }
    else
    {
        CAMX_LOG_INFO(CamxLogGroupSensor, "not releasing sensor device: cameraCloseStatus: %d", cameraCloseStatus);
    }

    // Destroy all the created objects.
    if (NULL != m_pPDLib)
    {
        PDLibDestroyParamList destroyParamList = { 0 };
        PDLibDestroyParam     destroyParams[PDLibDestroyParamTypeCount] = {};
        CAMX_ASSERT_MESSAGE(NULL != pStaticSettings, "pStaticSettings NULL pointer");

        UINT* pOverrideCameraClose                                                  =
            (UINT *)&pStaticSettings->overridePDLibClose;
        destroyParams[PDLibDestroyParamTypeCameraCloseIndicator].destroyParamType   = PDLibDestroyParamTypeCameraCloseIndicator;
        destroyParams[PDLibDestroyParamTypeCameraCloseIndicator].pParam             = static_cast<VOID*>(pOverrideCameraClose);
        destroyParams[PDLibDestroyParamTypeCameraCloseIndicator].sizeOfParam        = sizeof(UINT);

        StatsCameraInfo cameraInfo;
        cameraInfo.cameraId = m_cameraId;
        destroyParams[PDLibDestroyParamTypeCameraInfo].destroyParamType   = PDLibDestroyParamTypeCameraInfo;
        destroyParams[PDLibDestroyParamTypeCameraInfo].pParam             = static_cast<VOID*>(&cameraInfo);
        destroyParams[PDLibDestroyParamTypeCameraInfo].sizeOfParam        = sizeof(StatsCameraInfo);

        destroyParamList.paramCount = PDLibDestroyParamTypeCount;
        destroyParamList.pParamList = &destroyParams[0];
        m_pPDLib->PDLibDestroy(m_pPDLib, &destroyParamList);
        m_pPDLib = NULL;
    }

    if (NULL != m_pPDLibHandler)
    {
        CAMX_DELETE m_pPDLibHandler;
        m_pPDLibHandler = NULL;
    }

    if (NULL != m_signalSensorInit.pMutex)
    {
        m_signalSensorInit.pMutex->Destroy();
        m_signalSensorInit.pMutex = NULL;
    }

    if (NULL != m_signalSensorInit.pWaitCondition)
    {
        m_signalSensorInit.pWaitCondition->Destroy();
        m_signalSensorInit.pWaitCondition = NULL;
    }

    if (NULL != m_signalSensorConfig.pMutex)
    {
        m_signalSensorConfig.pMutex->Destroy();
        m_signalSensorConfig.pMutex = NULL;
    }

    if (NULL != m_signalSensorConfig.pWaitCondition)
    {
        m_signalSensorConfig.pWaitCondition->Destroy();
        m_signalSensorConfig.pWaitCondition = NULL;
    }

    if (NULL != m_signalSensorSubModules.pMutex)
    {
        m_signalSensorSubModules.pMutex->Destroy();
        m_signalSensorSubModules.pMutex = NULL;
    }

    if (NULL != m_signalSensorSubModules.pWaitCondition)
    {
        m_signalSensorSubModules.pWaitCondition->Destroy();
        m_signalSensorSubModules.pWaitCondition = NULL;
    }

    if (NULL != m_signalOISInit.pMutex)
    {
        m_signalOISInit.pMutex->Destroy();
        m_signalOISInit.pMutex = NULL;
    }

    if (NULL != m_signalOISInit.pWaitCondition)
    {
        m_signalOISInit.pWaitCondition->Destroy();
        m_signalOISInit.pWaitCondition = NULL;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::Create
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SensorNode* SensorNode::Create(
    const NodeCreateInputData* pCreateInputData,
    NodeCreateOutputData*      pCreateOutputData)
{
    SensorNode* pSensorNode = CAMX_NEW SensorNode;

    CAMX_UNREFERENCED_PARAM(pCreateOutputData);

    if (NULL != pSensorNode)
    {
        if (NULL != pCreateInputData->pPDLibCallbacks)
        {
            pSensorNode->m_pPDCallback = pCreateInputData->pPDLibCallbacks;
        }
        else
        {
            pSensorNode->m_pPDCallback = NULL;
        }
    }

    return pSensorNode;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::Destroy
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID SensorNode::Destroy()
{
    CAMX_DELETE this;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::ProcessingNodeInitialize
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::ProcessingNodeInitialize(
    const NodeCreateInputData* pCreateInputData,
    NodeCreateOutputData*      pCreateOutputData)
{

    CAMX_UNREFERENCED_PARAM(pCreateInputData);

    CamxResult result = CamxResultSuccess;

    CAMX_ENTRYEXIT_SCOPE(CamxLogGroupSensor, SCOPEEventSensorNodeProcessingNodeInitialize);

    pCreateOutputData->pNodeName = m_pNodeName;

    // register to update config done for initial PCR
    pCreateOutputData->createFlags.willNotifyConfigDone = TRUE;

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::CreateSubModules
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::CreateSubModules()
{
    CamxResult result              = CamxResultSuccess;
    SubDeviceProperty CSIPHYDevice = m_pSensorSubDevicesCache->GetSubDevice(m_cameraId, CSIPHYHandle);
    result = CSIPHYSubmodule::Create(m_pHwContext, &m_pCSIPHY, CSIPHYDevice.deviceIndex, m_cameraId);

    if (result != CamxResultSuccess)
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "CSIPhy Submodule creation failed");
        return result;
    }

    if (NULL == m_pCSIPHY)
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "CSIPhy Pointer is NULL");
        return CamxResultEInvalidPointer;
    }

    AddCSLDeviceHandle(m_pCSIPHY->GetDeviceHandle());
    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::PostPipelineCreate
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::PostPipelineCreate()
{
    CamxResult result = CamxResultSuccess;

    SensorPostJob* pSensorPostJob    = CAMX_NEW SensorPostJob;
    pSensorPostJob->pSensor          = this;
    pSensorPostJob->sensorJobCommand = SensorPostJobCommand::ConfigureSensor;
    VOID* pData[]                    = { pSensorPostJob, NULL };
    result                           = m_pThreadManager->PostJob(m_hJobFamilyHandle,
                                                                 NULL,
                                                                 &pData[0],
                                                                 FALSE,
                                                                 FALSE);

    SensorPostJob* pSensorPostJobCreateSubModules    = CAMX_NEW SensorPostJob;
    if (pSensorPostJobCreateSubModules != NULL)
    {
        pSensorPostJobCreateSubModules->pSensor = this;
        pSensorPostJobCreateSubModules->sensorJobCommand = SensorPostJobCommand::SubModulesCreate;
    }
    VOID* pSubModuleCreateData[]                     = { pSensorPostJobCreateSubModules, NULL };
    result                                           = m_pThreadManager->PostJob(m_hJobFamilyHandle,
                                                                                 NULL,
                                                                                 &pSubModuleCreateData[0],
                                                                                 FALSE,
                                                                                 FALSE);

    if (CamxResultSuccess == result)
    {
        CAMX_LOG_INFO(CamxLogGroupSensor, "PostPipelineCreate on Sensor successful!");
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "PostPipelineCreate on Sensor failed: %s", CamxResultStrings[result]);
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::PublishISO100GainInformation
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID SensorNode::PublishISO100GainInformation()
{

    FLOAT        ISO100Gain         = GetSensorDataObject()->GetISO100Gain(m_cameraId);
    const UINT   SensorOutputTags[] = { PropertyIDUsecaseSensorISO100Gain };
    const VOID*  pOutputData[1]     = { 0 };
    UINT         pDataCount[1]      = { 0 };
    pDataCount[0]                   = sizeof(FLOAT);
    pOutputData[0]                  = &ISO100Gain;
    WriteDataList(SensorOutputTags, pOutputData, pDataCount, 1);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::PublishSensorProperties
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID SensorNode::PublishSensorProperties()
{
    SensorProperties  sensorProperties = { 0 };
    LensInfo   lensInfo                = { 0 };

    UpdateLensInformation(&lensInfo);
    sensorProperties.sensingMethod          = GetSensorDataObject()->GetSensorSensingMethod();
    sensorProperties.focalLengthIn35mm      = GetSensorDataObject()->GetSensorCropFactor() * lensInfo.focalLength;
    UINT              SensorPropertiesTag[] = { PropertyIDSensorProperties};
    static const UINT TagSize               = CAMX_ARRAY_SIZE(SensorPropertiesTag);
    const VOID*       pData[TagSize]        = { 0 };
    UINT              pDataCount[TagSize]   = { 0 };
    UINT              dataIndex             = 0;
    pData[dataIndex]                        = &sensorProperties;
    pDataCount[dataIndex]                   = sizeof(SensorProperties);
    WriteDataList(SensorPropertiesTag, pData, pDataCount, TagSize);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::PopulatePDAFInformation
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID SensorNode::PopulatePDAFInformation()
{
    PDAFData*                    pPDAFData         = m_pSensorModuleData->GetPDAFDataObj();
    const PDAFConfigurationData* pPDAFConfigData   = NULL;
    UINT32                       index             = 0;
    UINT32                       resIdx            = m_currentResolutionIndex;
    CamxResult                   result = CamxResultSuccess;

    if (TRUE == m_isPDAFEnabled)
    {
        pPDAFConfigData = pPDAFData->GetPDAFConfigData();

        if (NULL != pPDAFConfigData)
        {
            m_sensorPDAFInfo.PDAFBlockHeight =
                pPDAFConfigData->PDSensorNativePatternInfo[resIdx].PDBlockPattern.PDBlockDimensions.height;
            m_sensorPDAFInfo.PDAFBlockWidth =
                pPDAFConfigData->PDSensorNativePatternInfo[resIdx].PDBlockPattern.PDBlockDimensions.width;
            m_sensorPDAFInfo.PDAFGlobaloffsetX =
                pPDAFConfigData->PDSensorNativePatternInfo[resIdx].PDBlockPattern.PDOffsetHorizontal;
            m_sensorPDAFInfo.PDAFGlobaloffsetY =
                pPDAFConfigData->PDSensorNativePatternInfo[resIdx].PDBlockPattern.PDOffsetVertical;
            m_sensorPDAFInfo.PDAFPixelCount =
                pPDAFConfigData->PDSensorNativePatternInfo[resIdx].PDBlockPattern.PDPixelCount;

            for (index = 0; index < m_sensorPDAFInfo.PDAFPixelCount; index++)
            {
                m_sensorPDAFInfo.PDAFPixelCoords[index].PDXCoordinate =
                    pPDAFConfigData->PDSensorNativePatternInfo[resIdx].PDBlockPattern.PDPixelCoordinates[index].PDXCoordinate;

                m_sensorPDAFInfo.PDAFPixelCoords[index].PDYCoordinate =
                    pPDAFConfigData->PDSensorNativePatternInfo[resIdx].PDBlockPattern.PDPixelCoordinates[index].PDYCoordinate;
            }
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::PublishPDAFInformation
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID SensorNode::PublishPDAFInformation()
{
    PDAFData* pPDAFData = m_pSensorModuleData->GetPDAFDataObj();

    if (TRUE == m_isPDAFEnabled)
    {
        // Publish SensorPDAFInfo to result pool for IFE/BPS modules
        const UINT  SensorOutputTags[]= { PropertyIDSensorPDAFInfo };
        const VOID* pOutputData[1]    = { 0 };
        UINT        pDataCount[1]     = { 0 };
        pDataCount[0]                 = sizeof(SensorPDAFInfo);
        pOutputData[0]                = &m_sensorPDAFInfo;
        WriteDataList(SensorOutputTags, pOutputData, pDataCount, 1);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::PublishCameraModuleInformation
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID SensorNode::PublishCameraModuleInformation()
{
    CamxResult                       result           = CamxResultSuccess;
    CameraConfigurationInformation   cameraModuleInfo = { 0 };
    HwCameraInfo                     cameraInfo;

    result = HwEnvironment::GetInstance()->GetCameraInfo(m_cameraId, &cameraInfo);

    if (CamxResultSuccess == result)
    {
        cameraModuleInfo.mountAngle       = cameraInfo.mountAngle;
        cameraModuleInfo.imageOrientation = cameraInfo.imageOrientation;
        result = m_pSensorModuleData->GetCameraPosition(&cameraModuleInfo.position);
    }

    if (CamxResultSuccess == result)
    {
        const UINT SensorOutputTags[] = { PropertyIDUsecaseCameraModuleInfo };
        const VOID* pOutputData[1]    = { 0 };
        UINT pDataCount[1]            = { 0 };
        pDataCount[0]                 = sizeof(CameraConfigurationInformation);
        pOutputData[0]                = &cameraModuleInfo;

        WriteDataList(SensorOutputTags, pOutputData, pDataCount, 1);
    }

    if (CamxResultSuccess != result)
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "Camera Module Information could not be published");
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::PublishLensInformation
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::PublishLensInformation()
{
    CamxResult result   = CamxResultSuccess;
    LensInfo   lensInfo = { 0 };

    result = UpdateLensInformation(&lensInfo);
    CAMX_ASSERT(CamxResultSuccess == result);

    const UINT SensorOutputTags[] = { PropertyIDUsecaseLensInfo };
    const VOID* pOutputData[1] = { 0 };
    UINT pDataCount[1] = { 0 };
    pDataCount[0] = sizeof(LensInfo);
    pOutputData[0] = &lensInfo;

    WriteDataList(SensorOutputTags, pOutputData, pDataCount, 1);

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::OnStreamOn
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::OnStreamOn()
{
    CamxResult result = CamxResultSuccess;

    CAMX_ENTRYEXIT_SCOPE(CamxLogGroupSensor, SCOPEEventSensorNodeOnStreamOn);

    m_signalSensorSubModules.pMutex->Lock();
    if ((SensorConfigurationStatus::SensorSubModuleCreateComplete != m_sensorConfigStatus) &&
        (SensorConfigurationStatus::SensorSubModuleCreateFailed != m_sensorConfigStatus))
    {
        m_signalSensorSubModules.pWaitCondition->Wait(m_signalSensorSubModules.pMutex->GetNativeHandle());
    }
    m_signalSensorSubModules.pMutex->Unlock();

    if (SensorConfigurationStatus::SensorSubModuleCreateComplete == m_sensorConfigStatus)
    {
        if ( TRUE == IsStatsNodeEnabled())
        {
            result = UpdateStartupExposureSettings();
            if (CamxResultSuccess == result)
            {
                UINT regSettingIdx = 0;
                UINT AECCmdSize = GetSensorDataObject()->GetI2CCmdSize(I2CRegSettingType::AEC,
                                  m_pRegSettings, 0, &regSettingIdx);
                CAMX_ASSERT(0 == (AECCmdSize % sizeof(UINT32)));
                result = CreateAndSubmitCommand(AECCmdSize,
                                                I2CRegSettingType::AEC,
                                                CSLPacketOpcodesSensorConfig,
                                                m_currentResolutionIndex,
                                                regSettingIdx);
            }
            if (CamxResultSuccess != result)
            {
                CAMX_LOG_ERROR(CamxLogGroupSensor, "Failed to configure startup exposure settings");
            }
        }
        else
        {
            CAMX_LOG_INFO(CamxLogGroupSensor, "Stats Node not available/enabled");
        }
    }
    else
    {
        result = CamxResultEFailed;
        CAMX_LOG_ERROR(CamxLogGroupSensor, "Creating submodules failed, cannot setup sensor");
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::PublishPerFrameSensorMetaData
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID SensorNode::PublishPerFrameSensorMetaData(
    UINT64 requestId)
{
    CamxResult           result                = CamxResultSuccess;
    SensorMetaData       metaData              = {0};
    SensorResolutionInfo resolutionInfo        = {0};
    ResolutionData*      pResolutionData       =
        &(GetSensorDataObject()->GetResolutionInfo())->resolutionData[m_currentResolutionIndex];
    FLOAT                ISPDigitalGain        = 0.0f;
    FLOAT                sensorAnalogRealGain  = 0.0f;
    FLOAT                sensorDigitalRealGain = 0.0f;
    FLOAT                lensFilterDensity     = 0.0f;
    FLOAT                lensAperture          = 0.0f;
    FLOAT                lensFocalLength       = 0.0f;
    RangeFLOAT           lensFocusRange        = {0};
    FLOAT                ISO100Gain            = 0.0f;
    VOID*                pRegControlInfo       = NULL;
    UINT                 numChannles           = 4;

    if ((NULL == m_pExposureInfo))
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "Invalid m_pExposureInfo: %p", m_pExposureInfo);
        return;
    }

    ISPDigitalGain        = GetSensorDataObject()->GetISPDigitalGain(m_pExposureInfo);
    sensorAnalogRealGain  = GetSensorDataObject()->GetAnalogRealGain(m_pExposureInfo);
    sensorDigitalRealGain = GetSensorDataObject()->GetDigitalRealGain(m_pExposureInfo);

    static const UINT PropertiesISO100Gain[] =
    {
        PropertyIDUsecaseSensorISO100Gain
    };
    VOID*  pISO100Gain[1]           = { 0 };
    UINT   length                   = CAMX_ARRAY_SIZE(PropertiesISO100Gain);
    UINT64 propertyDataOffset[1]    = { 0 };

    GetDataList(PropertiesISO100Gain, pISO100Gain, propertyDataOffset, length);
    if (NULL != pISO100Gain[0])
    {
        ISO100Gain  = *reinterpret_cast<FLOAT*>(pISO100Gain[0]);
    }

    for (UINT32 index = 0; index < pResolutionData->streamInfo.streamConfigurationCount; index++)
    {
        if (StreamType::IMAGE == pResolutionData->streamInfo.streamConfiguration[index].type)
        {
            metaData.width  = pResolutionData->streamInfo.streamConfiguration[index].frameDimension.width -
                              pResolutionData->cropInfo.left -
                              pResolutionData->cropInfo.right;
            metaData.height = pResolutionData->streamInfo.streamConfiguration[index].frameDimension.height -
                              pResolutionData->cropInfo.top -
                              pResolutionData->cropInfo.bottom;
        }
    }

    metaData.exposureTime       = GetSensorDataObject()->GetExposureTime(m_sensorParam.currentExposure, pRegControlInfo);
    metaData.sensorGain         = sensorAnalogRealGain * sensorDigitalRealGain;

    metaData.frameLengthLines   = m_sensorParam.currentFrameLengthLines;
    metaData.sensitivity        = GetSensorDataObject()->GainToSensitivity(metaData.sensorGain, ISO100Gain, pRegControlInfo);

    metaData.filterArrangement  = GetSensorDataObject()->GetColorFilterPattern(m_currentResolutionIndex);
    metaData.rollingShutterSkew = GetSensorDataObject()->GetRollingShutterSkew(metaData.height,
                                                                               m_currentResolutionIndex);
    metaData.shortExposureTime  = GetSensorDataObject()->GetExposureTime(m_sensorParam.currentShortExposure, pRegControlInfo);
    metaData.shortSensorGain    = m_sensorParam.currentShortGain;

    /// @todo (CAMX-2766) - Support for test pattern modes.
    metaData.testPatternMode    = static_cast<INT32>(TestPatternMode::OFF);

    metaData.frameDuration      = GetSensorDataObject()->GetFrameReadoutTime(m_sensorParam.currentFrameLengthLines,
                                                                             m_currentResolutionIndex);

    // Sanity check: Frame Duration should not be smaller than duration for max fps for the resolution.
    UINT16 maxFps               = static_cast<UINT16>(GetSensorDataObject()->GetMaxFPS(m_currentResolutionIndex));
    if (metaData.frameDuration < NanoSecondsPerSecond/maxFps)
    {
        metaData.frameDuration = static_cast<UINT64>(NanoSecondsPerSecond/maxFps);
    }

    DOUBLE noiseProfile[8] = { 0 };
    DOUBLE entryS          = GetSensorDataObject()->GetNoiseModelEntryS(metaData.sensitivity);
    DOUBLE entryO          = GetSensorDataObject()->GetNoiseModelEntryO(metaData.sensitivity, ISO100Gain);

    CAMX_LOG_VERBOSE(CamxLogGroupSensor, "noiseS= %e noiseO = %e", entryS, entryO);

    for (UINT32 index = 0; index < (numChannles * 2); (index = index + 2))
    {
        noiseProfile[index]     = entryS;
        noiseProfile[index + 1] = entryO;
        CAMX_LOG_VERBOSE(CamxLogGroupSensor, "noiseS[%d]= %e, noiseO[%d]= %e", index, entryS, index + 1, entryO);
    }

    CAMX_LOG_VERBOSE(CamxLogGroupSensor,
                     "Publishing metadata: ReqId: %llu resID %d rollingShutterSkew: %llu ,"
                     "frameDuration: %llu, exposureTime:%llu, sensitivity: %d, sensorGain: %f, ispDigitalGain: %f",
                     requestId,
                     m_currentResolutionIndex,
                     metaData.rollingShutterSkew,
                     metaData.frameDuration,
                     metaData.exposureTime,
                     metaData.sensitivity,
                     metaData.sensorGain,
                     ISPDigitalGain);

    resolutionInfo.vtPixelClk          = GetSensorDataObject()->GetVTPixelClk(m_currentResolutionIndex);
    resolutionInfo.lineLengthPixelClk  = GetSensorDataObject()->GetLineLengthPixelClk(m_currentResolutionIndex);
    resolutionInfo.frameRate           = static_cast<FLOAT>(GetSensorDataObject()->GetMaxFPS(m_currentResolutionIndex));
    resolutionInfo.frameLengthLine     = GetSensorDataObject()->GetFrameLengthLines(m_currentResolutionIndex);

    UINT SensorMetaDataTags[] =
    {
        PropertyIDSensorMetaData,
        PropertyIDSensorResolutionInfo,
        PropertyIDPostSensorGainId,
        PropertyIDSensorCurrentMode,
        SensorSensitivity,
        SensorTestPatternMode,
        SensorFrameDuration,
        SensorRollingShutterSkew,
        SensorExposureTime,
        SensorGreenSplit,
        SensorNoiseProfile,
        0,
        0,
    };

    static const UINT NumSensorMetaDataTags             = CAMX_ARRAY_SIZE(SensorMetaDataTags);
    const VOID*       pData[NumSensorMetaDataTags]      = { 0 };
    UINT              pDataCount[NumSensorMetaDataTags] = { 0 };
    UINT              dataIndex                         = 0;
    UINT              metaTag                           = 0;

    pData[dataIndex]        = &metaData;
    pDataCount[dataIndex++] = sizeof(SensorMetaData);

    pData[dataIndex]        = &resolutionInfo;
    pDataCount[dataIndex++] = sizeof(resolutionInfo);

    pData[dataIndex]        = &ISPDigitalGain;
    pDataCount[dataIndex++] = sizeof(FLOAT);

    pData[dataIndex]        = &m_currentResolutionIndex;
    pDataCount[dataIndex++] = sizeof(m_currentResolutionIndex);

    pData[dataIndex]        = &(metaData.sensitivity);
    pDataCount[dataIndex++] = 1;

    pData[dataIndex]        = &(metaData.testPatternMode);
    pDataCount[dataIndex++] = 1;

    pData[dataIndex]        = &(metaData.frameDuration);
    pDataCount[dataIndex++] = 1;

    pData[dataIndex]        = &(metaData.rollingShutterSkew);
    pDataCount[dataIndex++] = 1;

    pData[dataIndex]        = &(metaData.exposureTime);
    pDataCount[dataIndex++] = 1;

    pData[dataIndex]        = &(m_opt_wb_grgb);
    pDataCount[dataIndex++] = 1;

    pData[dataIndex]        = &(noiseProfile);
    pDataCount[dataIndex++] = (numChannles * 2);

    result = VendorTagManager::QueryVendorTagLocation("com.qti.sensorbps", "mode_index", &metaTag);
    CAMX_ASSERT_MESSAGE(CamxResultSuccess == result, "Failed to get vendor tag: mode_index");

    SensorMetaDataTags[dataIndex] = metaTag;
    pData[dataIndex]              = &m_currentResolutionIndex;
    pDataCount[dataIndex++]       = 1;

    result = VendorTagManager::QueryVendorTagLocation("com.qti.sensorbps", "gain", &metaTag);
    CAMX_ASSERT_MESSAGE(CamxResultSuccess == result, "Failed to get vendor tag: gain");

    SensorMetaDataTags[dataIndex] = metaTag;
    pData[dataIndex]              = &ISPDigitalGain;
    pDataCount[dataIndex++]       = 1;

    WriteDataList(SensorMetaDataTags, pData, pDataCount, NumSensorMetaDataTags);
    const LensInformation* pLensInformation = m_pSensorModuleData->GetLensInfo();
    if (NULL == pLensInformation)
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "Lens Information is NULL");
        return;
    }

    // LensAperture metadata is represented as float, not double
    lensAperture       = static_cast<FLOAT>(pLensInformation->fNumber);

    // LensFocalLength metadata is represented as float, not double
    lensFocalLength    = static_cast<FLOAT>(pLensInformation->focalLength);

    lensFocusRange.max = static_cast<FLOAT>(pLensInformation->maxFocusDistance);
    lensFocusRange.min = static_cast<FLOAT>(pLensInformation->minFocusDistance);

    UINT LensInfoMetaDataTags[] =
    {
        LensAperture,
        LensFilterDensity,
        LensFocalLength,
        LensFocusRange,
    };

    static const UINT NumLensInfoMetaDataTags = CAMX_ARRAY_SIZE(LensInfoMetaDataTags);
    const VOID*       pLensData[NumLensInfoMetaDataTags] = { 0 };
    UINT              pLensDataCount[NumLensInfoMetaDataTags] = { 0 };
    dataIndex = 0;

    pLensData[dataIndex] = &lensAperture;
    pLensDataCount[dataIndex++] = 1;

    pLensData[dataIndex]        = &lensFilterDensity;
    pLensDataCount[dataIndex++] = 1;

    pLensData[dataIndex]        = &lensFocalLength;
    pLensDataCount[dataIndex++] = 1;

    pLensData[dataIndex]        = &(lensFocusRange);
    pLensDataCount[dataIndex++] = 2;

    WriteDataList(LensInfoMetaDataTags, pLensData, pLensDataCount, NumLensInfoMetaDataTags);

    LensOpticalStabilizationModeValues oisEnable = LensOpticalStabilizationModeOff;
    static const UINT MetadataOIS[] =
    {
        InputLensOpticalStabilizationMode
    };

    VOID* pOisGetData[1]            = { 0 };
    UINT64 propertyDataOisOffset[1] = { 0 };

    GetDataList(MetadataOIS, pOisGetData, propertyDataOisOffset, 1);
    if (NULL != pOisGetData[0])
    {
        oisEnable = *(static_cast<LensOpticalStabilizationModeValues*>(pOisGetData[0]));
    }

    static const UINT OISResultMetaDataTag[] =
    {
        LensOpticalStabilizationMode
    };
    const VOID* pOisData[1]      = { 0 };
    UINT        pOisDataCount[1] = { 0 };

    pOisData[0]      = &oisEnable;
    pOisDataCount[0] = 1;

    WriteDataList(OISResultMetaDataTag, pOisData, pOisDataCount, 1);

    if (TRUE == pResolutionData->integrationInfoExists)
    {
        UINT        IntegrationInfoTags[] = { 0 };
        const VOID* pIntegrationData[1]   = { 0 };
        UINT        pIntegrationDataCount[1]         = { 0 };

        result = VendorTagManager::QueryVendorTagLocation("org.codeaurora.qcamera3.sensor_meta_data",
                                                          "integration_information",
                                                          &metaTag);
        CAMX_ASSERT_MESSAGE(CamxResultSuccess == result, "Failed to get vendor tag: integration_information");

        IntegrationInfoTags[0]      = metaTag;
        pIntegrationData[0]         = &pResolutionData->integrationInfo;
        pIntegrationDataCount[0]    = sizeof(IntegrationInformation) / sizeof(UINT32);
        WriteDataList(IntegrationInfoTags, pIntegrationData, pIntegrationDataCount, 1);
    }

    PublishPDAFInformation();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::UpdateSensorExposure
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID SensorNode::UpdateSensorExposure(
    BOOL              applyShortExposure,
    SensorParam*      pExposureParameters,
    AECFrameControl*  pAECOutput)
{
    if ((NULL != pAECOutput) && (NULL != pExposureParameters))
    {
        if (TRUE == applyShortExposure)
        {
            pExposureParameters->currentGain          = pAECOutput->exposureInfo[ExposureIndexLong].linearGain;
            pExposureParameters->currentExposure      = pAECOutput->exposureInfo[ExposureIndexLong].exposureTime;
            pExposureParameters->currentShortGain     = pAECOutput->exposureInfo[ExposureIndexShort].linearGain;
            pExposureParameters->currentShortExposure = pAECOutput->exposureInfo[ExposureIndexShort].exposureTime;
        }
        else
        {
            pExposureParameters->currentGain          = pAECOutput->exposureInfo[ExposureIndexShort].linearGain;
            pExposureParameters->currentExposure      = pAECOutput->exposureInfo[ExposureIndexShort].exposureTime;
            pExposureParameters->currentShortGain     = 0;
            pExposureParameters->currentShortExposure = 0;
        }
    }
    pExposureParameters->currentFrameLengthLines      = GetSensorDataObject()->GetFrameLengthLines(m_currentResolutionIndex);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::NotifyCSLMessage
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::NotifyCSLMessage(
    CSLMessage* pCSLMessage)
{
    CamxResult result = CamxResultSuccess;

    if (CSLMessageType::CSLMessageTypeFrame == pCSLMessage->type)
    {
        UINT32 getProps[]                         = {SensorExposureTime};
        UINT64 offsets[CAMX_ARRAY_SIZE(getProps)] = {0};
        VOID*  pData[CAMX_ARRAY_SIZE(getProps)]   = {0};
        UINT64 exposureStartTime                  = 0;

        result = GetDataList(getProps, pData, offsets, CAMX_ARRAY_SIZE(getProps));
        if ((CamxResultSuccess == result) && (NULL != pData[0]))
        {
            exposureStartTime = GetSensorDataObject()->GetExposureStartTime(pCSLMessage->message.frameMessage.timestamp,
                                                                            *reinterpret_cast<UINT64*>(pData[0]),
                                                                            m_currentResolutionIndex);

            UINT32      writeProps[]                            = {PropertyIDSensorExposureStartTime};
            UINT32      count[CAMX_ARRAY_SIZE(writeProps)]      = {sizeof(UINT64)};
            const VOID* pWriteData[CAMX_ARRAY_SIZE(writeProps)] = {&exposureStartTime};

            result = WriteDataList(writeProps, pWriteData, count, CAMX_ARRAY_SIZE(writeProps));

            CAMX_LOG_VERBOSE(CamxLogGroupSensor,
                         "requestID: %llu, sofTimestamp: %lld, exposure start time: %lld",
                         pCSLMessage->message.frameMessage.requestID,
                         pCSLMessage->message.frameMessage.timestamp,
                         exposureStartTime);
        }
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::SetDependencies
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::SetDependencies(
    NodeProcessRequestData* pNodeProcessRequestData)
{
    CamxResult      result      = CamxResultSuccess;
    DependencyUnit* pDependency = &pNodeProcessRequestData->dependencyInfo[0];
    UINT64          requestId   = pNodeProcessRequestData->pCaptureRequest->requestId;
    UINT            count       = 0;

    CAMX_LOG_VERBOSE(CamxLogGroupSensor, "Sensor: ProcessRequest: Setting dependency for Req#%llu", requestId);

    // Set a dependency on the completion of the previous ExecuteProcessRequest() call
    // so that we can guarantee serialization of all ExecuteProcessRequest() calls for this node.
    // Needed since the ExecuteProcessRequest() implementation is not reentrant.
    // Remove when requirement CAMX-3030 is implemented.
    // Skip setting dependency for first request
    if (FirstValidRequestId < requestId)
    {
        pDependency->dependencyFlags.hasPropertyDependency = TRUE;
        pDependency->propertyDependency.properties[count]  = GetNodeCompleteProperty();
        // Always point to the previous request. Should NOT be tied to the pipeline delay!
        pDependency->propertyDependency.offsets[count]     = 1;
        pDependency->processSequenceId                     = 1;
        count++;
    }

    pDependency->dependencyFlags.hasPropertyDependency                      = TRUE;
    pDependency->propertyDependency.properties[count++]                     = PropertyIDAECFrameControl;
    pDependency->processSequenceId                                          = 1;
    pDependency->propertyDependency.count                                   = count;

    pDependency->propertyDependency.properties[count++]                     = PropertyIDAFFrameControl;
    pDependency->processSequenceId                                          = 1;
    pDependency->propertyDependency.count                                   = count;

    UINT32          regControlMetaTag = 0;
    result = VendorTagManager::QueryVendorTagLocation("org.quic.camera2.sensor_register_control",
                                                      "sensor_register_control",
                                                      &regControlMetaTag);
    if (0 != regControlMetaTag)
    {
        pDependency->propertyDependency.properties[count++]                 = regControlMetaTag;
        pDependency->processSequenceId                                      = 1;
        pDependency->propertyDependency.count                               = count;
    }

    if ((TRUE == GetStaticSettings()->enableSensorFpsMatch) && (TRUE == m_isMultiCameraUsecase) &&
        (TRUE != m_isMasterCamera))
    {
        MultiRequestSyncData*  pMultiRequestData = pNodeProcessRequestData->pCaptureRequest->pMultiRequestData;
        INT64                  lpmRequestDelta   = requestId - pMultiRequestData->requestID[m_peerPipelineId];
        BOOL                   negate            = static_cast<BOOL>(lpmRequestDelta <= 0);

        pDependency->propertyDependency.properties[count]                   = PropertyIDSensorMetaData;
        pDependency->propertyDependency.negate[count]                       = negate;
        pDependency->propertyDependency.pipelineIds[count]                  = m_peerPipelineId;
        pDependency->propertyDependency.offsets[count++]                    = static_cast<UINT64>(abs(lpmRequestDelta));

        pDependency->propertyDependency.properties[count]                   = PropertyIDSensorResolutionInfo;
        pDependency->propertyDependency.negate[count]                       = negate;
        pDependency->propertyDependency.pipelineIds[count]                  = m_peerPipelineId;
        pDependency->propertyDependency.offsets[count++]                    = static_cast<UINT64>(abs(lpmRequestDelta));

        pDependency->propertyDependency.count                               = count;
        CAMX_LOG_VERBOSE(CamxLogGroupSensor, "Sensor: Setting dependency for fps match, req#%llu", requestId);
    }

    pNodeProcessRequestData->numDependencyLists                             = 1;

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::ExecuteProcessRequest
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::ExecuteProcessRequest(
    ExecuteProcessRequestData* pExecuteProcessRequestData)
{
    CamxResult         result         = CamxResultEFailed;
    TuningDataManager* pTuningManager = NULL;

    CAMX_ENTRYEXIT_SCOPE_ID(CamxLogGroupISP, SCOPEEventSensorNodeExecuteProcessRequest,
        pExecuteProcessRequestData->pNodeProcessRequestData->pCaptureRequest->requestId);

    CAMX_ASSERT(NULL != pExecuteProcessRequestData);
    CAMX_ASSERT(NULL != pExecuteProcessRequestData->pNodeProcessRequestData);
    CAMX_ASSERT(NULL != pExecuteProcessRequestData->pNodeProcessRequestData->pCaptureRequest);

    UINT32          regControlMetaTag       = 0;

    result = VendorTagManager::QueryVendorTagLocation("org.quic.camera2.sensor_register_control",
                                                      "sensor_register_control",
                                                      &regControlMetaTag);

    UINT64                requestId          = pExecuteProcessRequestData->pNodeProcessRequestData->pCaptureRequest->requestId;
    DependencyUnit*       pDependency        = &pExecuteProcessRequestData->pNodeProcessRequestData->dependencyInfo[0];
    BOOL                  applyShortExposure = FALSE;

    if ((FirstValidRequestId == requestId) && (0 == pExecuteProcessRequestData->pNodeProcessRequestData->processSequenceId))
    {
        InitializeMultiCameraInfo();
    }

    if (TRUE == m_isMultiCameraUsecase)
    {
        m_isMasterCamera = IsMasterCamera();
    }

    // Update the sensor mode per frame
    static const UINT PropertiesForSensorInputs[] =
    {
        PropertyIDSensorCurrentMode,
    };

    static const UINT NumSensorInputs                   = CAMX_ARRAY_SIZE(PropertiesForSensorInputs);
    VOID*  pSensorData[NumSensorInputs]                 = { 0 };
    UINT64 propertySensorDataOffset[NumSensorInputs]    = { 0 };
    UINT*  pCurrentSensorMode                           = NULL;
    BOOL   bShouldSetDependency                         = FALSE;
    const StaticSettings* pStaticSettings               = GetStaticSettings();
    AECFlashInfoType flashType                          = FlashInfoTypeOff;
    UINT32           LEDCurrents[LEDSettingCount]       = { 0 };

    GetDataList(PropertiesForSensorInputs, pSensorData, propertySensorDataOffset, NumSensorInputs);

    pTuningManager = GetTuningDataManager();

    CAMX_ASSERT(pSensorData[0] != NULL);

    if (TRUE == pStaticSettings->perFrameSensorMode)
    {
        if (pCurrentSensorMode != NULL)
        {
            m_currentResolutionIndex = *pCurrentSensorMode;
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Current Sensor Mode pointer is NULL");
            return CamxResultEInvalidPointer;
        }
    }
    applyShortExposure = GetSensorDataObject()->IsHDRMode(m_currentResolutionIndex);

    if (0 == pExecuteProcessRequestData->pNodeProcessRequestData->processSequenceId)
    {
        // Publish flash metadata ASAP if flash is unavailable to meet the early metadata.
        if (NULL == m_pFlash)
        {
            static FlashStateValues flashState               = FlashStateUnavailable;
            static FlashModeValues  flashMode                = FlashModeOff;
            static UINT             flashTags[]              = { FlashState, FlashMode };
            static const UINT       NumFlashTags             = CAMX_ARRAY_SIZE(flashTags);
            const VOID*             pData[NumFlashTags]      = { &flashState, &flashMode };
            UINT                    pDataCount[NumFlashTags] = { 1, 1 };

            WriteDataList(flashTags, pData, pDataCount, NumFlashTags);
        }

        // If AEC stats processing is enabled and we're being called for the first time, only setup dependencies.
        if (TRUE == IsStatsNodeEnabled())
        {
            bShouldSetDependency = TRUE;
        }
    }

    if (TRUE == bShouldSetDependency)
    {
        result = SetDependencies(pExecuteProcessRequestData->pNodeProcessRequestData);
    }
    else
    {
        if (FALSE == IsStatsNodeEnabled())
        {
            FLOAT ISO100Gain = GetSensorDataObject()->GetISO100Gain(m_cameraId);
            UINT InputAECData[] =
            {
                InputSensorExposureTime,   // 0
                InputSensorSensitivity,    // 1
                InputSensorFrameDuration,  // 2
            };

            static const UINT   InputLength                  = CAMX_ARRAY_SIZE(InputAECData);
            VOID*               pInputData[InputLength]      = { 0 };
            UINT64              pInputDataCount[InputLength] = { 0 };

            GetDataList(InputAECData, pInputData, pInputDataCount, InputLength);

            SensorParam updateParam     = { 0 };
            updateParam.pRegControlData = NULL;
            updateParam.currentExposure = updateParam.currentShortExposure =
                *(static_cast<UINT64*>(pInputData[0]));
            updateParam.currentGain     = updateParam.currentShortGain =
                GetSensorDataObject()->SensitivityToGain(*(static_cast<INT32*>(pInputData[1])), ISO100Gain);

            // Apply HAL override of frameLengthLines (aka frame duration) if provided
            UINT64 inputFrameDuration = (NULL != pInputData[2] ? *(static_cast<UINT64*>(pInputData[2])) : 0);
            if (0 != inputFrameDuration)
            {
                updateParam.currentFrameLengthLines = GetSensorDataObject()->ExposureToLineCount(
                    inputFrameDuration, m_currentResolutionIndex);
                if (FALSE == GetStaticSettings()->disableFpsLimits)
                {
                    updateParam.currentFrameLengthLines = Utils::MaxUINT32(updateParam.currentFrameLengthLines,
                        GetSensorDataObject()->GetFrameLengthLines(m_currentResolutionIndex));
                    updateParam.currentFrameLengthLines = Utils::MinUINT32(updateParam.currentFrameLengthLines,
                        GetSensorDataObject()->GetMaxFrameLengthLines(m_currentResolutionIndex));
                }

                CAMX_LOG_VERBOSE(CamxLogGroupSensor,
                    "Hal override frameLengthLines min:result:max %u:%u:%u disableFpsLimits %d",
                    GetSensorDataObject()->GetFrameLengthLines(m_currentResolutionIndex),
                    updateParam.currentFrameLengthLines,
                    GetSensorDataObject()->GetMaxFrameLengthLines(m_currentResolutionIndex),
                    GetStaticSettings()->disableFpsLimits);
            }
            else
            {
                updateParam.currentFrameLengthLines = GetSensorDataObject()->GetFrameLengthLines(m_currentResolutionIndex);
            }

            PrepareSensorUpdate(&updateParam, pExecuteProcessRequestData->pNodeProcessRequestData);

            CAMX_LOG_VERBOSE(CamxLogGroupSensor,
                "Sensor: Update Exposure from input pool: Gain:%f ExpTime:%ld, short Gain:%f, short ExpTime:%ld FLL:%u",
                updateParam.currentGain,
                updateParam.currentExposure,
                updateParam.currentShortGain,
                updateParam.currentShortExposure,
                updateParam.currentFrameLengthLines);

            m_sensorParam.currentGain             = updateParam.currentGain;
            m_sensorParam.currentExposure         = updateParam.currentExposure;
            m_sensorParam.currentLineCount        = updateParam.currentLineCount;
            m_sensorParam.currentFrameLengthLines = updateParam.currentFrameLengthLines;
            m_sensorParam.currentShortGain        = updateParam.currentShortGain;
            m_sensorParam.currentShortExposure    = updateParam.currentShortExposure;
            m_sensorParam.currentShortLineCount   = updateParam.currentShortLineCount;

            result = ApplySensorUpdate(requestId);

            if (CamxResultSuccess == result)
            {
                m_sensorParam.previousGain             = m_sensorParam.currentGain;
                m_sensorParam.previousExposure         = m_sensorParam.currentExposure;
                m_sensorParam.previousLineCount        = m_sensorParam.currentLineCount;
                m_sensorParam.previousFrameLengthLines = m_sensorParam.currentFrameLengthLines;
                m_sensorParam.previousShortGain        = m_sensorParam.currentShortGain;
                m_sensorParam.previousShortExposure    = m_sensorParam.currentShortExposure;
                m_sensorParam.previousShortLineCount   = m_sensorParam.currentShortLineCount;
            }
        }
        else
        {
            // We previously queued to DRQ with a prop, it must be available now
            static const UINT Properties[]               =
            {
                PropertyIDAECFrameControl,
                regControlMetaTag,
                PropertyIDAFFrameControl,
            };
            const UINT  propLength                          = CAMX_ARRAY_SIZE(Properties);
            VOID*       pData[propLength]                   = { 0 };
            UINT64      propertyDataOffset[propLength]      = { 0 };
            SensorParam updateParam                         = { 0 };

            GetDataList(Properties, pData, propertyDataOffset, propLength);

            CAMX_ASSERT(pData[0] != NULL);

            AECFrameControl*   pAECOutput       = reinterpret_cast<AECFrameControl*>(pData[0]);
            updateParam.pRegControlData         = reinterpret_cast<AECAlgoAdditionalInfo*>(pData[1]);
            AFFrameControl*    pFrameControl    = NULL;
            PDLibWindowConfig* pPDAFWindowConfig = NULL;
            BOOL               applyPdafData     = FALSE;

            if (NULL != pData[2])
            {
                pFrameControl       = reinterpret_cast<AFFrameControl*>(pData[2]);
                pPDAFWindowConfig   = &(pFrameControl->PDLibROI);
            }
            else
            {
                CAMX_LOG_INFO(CamxLogGroupSensor, "Failed to get PropertyIDAFFrameControl");
            }

            if (NULL != pPDAFWindowConfig)
            {
                CAMX_LOG_VERBOSE(CamxLogGroupSensor, "PDLibROI type %d, [%f %f %f %f], hnum %d vnum %d residx = %d",
                                                                pPDAFWindowConfig->roiType,
                                                                pPDAFWindowConfig->fixedAFWindow.startX,
                                                                pPDAFWindowConfig->fixedAFWindow.startY,
                                                                pPDAFWindowConfig->fixedAFWindow.endX,
                                                                pPDAFWindowConfig->fixedAFWindow.endY,
                                                                pPDAFWindowConfig->horizontalWindowCount,
                                                                pPDAFWindowConfig->verticalWindowCount,
                                                                m_currentResolutionIndex);

                if ((0.0 == pPDAFWindowConfig->fixedAFWindow.startX) &&
                   (0.0 == pPDAFWindowConfig->fixedAFWindow.startY) &&
                   (0.0 == pPDAFWindowConfig->fixedAFWindow.endX) &&
                   (0.0 == pPDAFWindowConfig->fixedAFWindow.endY))
                {
                    CAMX_LOG_VERBOSE(CamxLogGroupSensor, "PDLibROI are all Zeros");
                }
                else
                {
                    PrepareSensorPDAFUpdate(pPDAFWindowConfig);
                }
            }

            flashType       = pAECOutput->flashInfo;
            LEDCurrents[0]  = pAECOutput->LEDCurrents[0];
            LEDCurrents[1]  = pAECOutput->LEDCurrents[1];

            UpdateSensorExposure(applyShortExposure, &updateParam, pAECOutput);
            CAMX_LOG_INFO(CamxLogGroupSensor,
                             "Sensor[%d]: ProcessRequest: ApplyGains: RequestID=%llu Gain:ExpTime =%f : %llu "
                             "Short Gain:ExpTime =%f : %llu LuxIdx = %f, LED Currents = %d : %d",
                             m_cameraId,
                             requestId,
                             updateParam.currentGain,
                             updateParam.currentExposure,
                             updateParam.currentShortGain,
                             updateParam.currentShortExposure,
                             pAECOutput->luxIndex,
                             pAECOutput->LEDCurrents[0],
                             pAECOutput->LEDCurrents[1]);

            PrepareSensorUpdate(&updateParam, pExecuteProcessRequestData->pNodeProcessRequestData);

            m_sensorParam.currentGain             = updateParam.currentGain;
            m_sensorParam.currentExposure         = updateParam.currentExposure;
            m_sensorParam.currentLineCount        = updateParam.currentLineCount;
            m_sensorParam.currentFrameLengthLines = updateParam.currentFrameLengthLines;
            m_sensorParam.currentShortGain        = updateParam.currentShortGain;
            m_sensorParam.currentShortExposure    = updateParam.currentShortExposure;
            m_sensorParam.currentShortLineCount   = updateParam.currentShortLineCount;

            result = ApplySensorUpdate(requestId);

            if (CamxResultSuccess == result)
            {
                m_sensorParam.previousGain             = m_sensorParam.currentGain;
                m_sensorParam.previousExposure         = m_sensorParam.currentExposure;
                m_sensorParam.previousLineCount        = m_sensorParam.currentLineCount;
                m_sensorParam.previousFrameLengthLines = m_sensorParam.currentFrameLengthLines;
                m_sensorParam.previousShortGain        = m_sensorParam.currentShortGain;
                m_sensorParam.previousShortExposure    = m_sensorParam.currentShortExposure;
                m_sensorParam.previousShortLineCount   = m_sensorParam.currentShortLineCount;

                m_prevSensorPdafData.PDAFroiType           = m_sensorPdafData.PDAFroiType;
                m_prevSensorPdafData.PDAFstartX            = m_sensorPdafData.PDAFstartX;
                m_prevSensorPdafData.PDAFstartY            = m_sensorPdafData.PDAFstartY;
                m_prevSensorPdafData.PDAFendX              = m_sensorPdafData.PDAFendX;
                m_prevSensorPdafData.PDAFendY              = m_sensorPdafData.PDAFendY;
                m_prevSensorPdafData.horizontalWindowCount = m_sensorPdafData.horizontalWindowCount;
                m_prevSensorPdafData.verticalWindowCount   = m_sensorPdafData.verticalWindowCount;
            }

            pDependency->dependencyFlags.dependencyFlagsMask = 0;
        }

        PublishPerFrameSensorMetaData(requestId);

        if (NULL != m_pFlash)
        {
            result = m_pFlash->ExecuteProcessRequest(pExecuteProcessRequestData, flashType, LEDCurrents, pTuningManager);
        }
    }

    if ((CamxResultSuccess == result) && (NULL != m_pOis))
    {
        // Submit packet will fail if there is no OIS hardware failing the sensor
        // Execute process request
        // Hence not checking the result of execute process request.
        CAMX_LOG_VERBOSE(CamxLogGroupSensor, "OIS execute process request called");
        m_pOis->ExecuteProcessRequest(pExecuteProcessRequestData);
    }

    PublishSensorProperties();

    if (CamxResultSuccess == result)
    {
        if (0 == pDependency->dependencyFlags.dependencyFlagsMask)
        {
            ProcessMetadataDone(requestId);
            ProcessRequestIdDone(requestId);
        }
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "ProcessRequest on Sensor failed: %s", CamxResultStrings[result]);
    }

    /// @todo (CAMX-2000) Finalize the decision if we want to enforce sensor position when AF is not in the topology as well.
    ///       Current code only override MoveLens functionality when update from AF is triggered.
    ///
    /// If manual logical lens position is enforced, trigger an initial lens position update regardless of AF availability
    /// if ((AFManualLensControlLogical == GetStaticSettings()->manualAf) &&
    ///     (requestId                  == FirstValidRequestId)           &&
    ///     (CamxResultSuccess          == result))
    /// {
    ///     m_pActuator->OnPropertyUpdate(PropertyIDMoveLens, requestId);
    /// }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SensorNode::InitializeMultiCameraInfo
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::InitializeMultiCameraInfo()
{
    CamxResult result = CamxResultSuccess;

    UINT32     numberOfCamerasRunning;
    BOOL       isMasterCamera;

    result = GetMultiCameraInfo(&m_isMultiCameraUsecase, &numberOfCamerasRunning, &isMasterCamera);

    if ((CamxResultSuccess == result) && (TRUE == m_isMultiCameraUsecase))
    {
        Pipeline* pPipeline = GetPipeline();

        if (NULL != pPipeline)
        {
            result = pPipeline->GetIntraRealtimePipelineId(pPipeline->GetPipelineId(), &m_peerPipelineId);
        }
    }
    CAMX_LOG_INFO(CamxLogGroupSensor, "m_isMultiCameraUsecase=%d, isMasterCamera=%d, peerPipelineId=%d",
        m_isMultiCameraUsecase, isMasterCamera, m_peerPipelineId);

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SensorNode::IsMasterCamera
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL SensorNode::IsMasterCamera()
{
    CamxResult result                  = CamxResultSuccess;
    BOOL       isMasterCamera          = TRUE;
    UINT32*    pTmp                    = NULL;
    UINT32     masterCameraTag         = 0;

    result = VendorTagManager::QueryVendorTagLocation("com.qti.chi.multicamerainfo", "MasterCamera", &masterCameraTag);

    if (CamxResultSuccess == result)
    {
        masterCameraTag |= InputMetadataSectionMask;

        const UINT propertyTag[]     = { masterCameraTag };
        VOID*      pData[1]          = { 0 };
        UINT64     propertyOffset[1] = { 0 };
        UINT       length            = CAMX_ARRAY_SIZE(propertyTag);

        result = GetDataList(propertyTag, pData, propertyOffset, length);

        if (NULL != pData[0])
        {
            pTmp           = static_cast<UINT32 *>(pData[0]);
            isMasterCamera = static_cast<BOOL>(*pTmp);
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Get MasterCamera vendor tag data failed");
        }
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor,
            "MasterCamera vendor tags location not available %d",
            masterCameraTag);
    }

    return isMasterCamera;
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SensorNode::AdjustSlaveCameraExposureInfo
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID SensorNode::AdjustSlaveCameraExposureInfo(
    SensorParam* pSensorParam,
    NodeProcessRequestData* pNodeProcessRequestData)
{
    CamxResult            result = CamxResultSuccess;
    UINT64                requestId = pNodeProcessRequestData->pCaptureRequest->requestId;
    MultiRequestSyncData* pMultiRequestData = pNodeProcessRequestData->pCaptureRequest->pMultiRequestData;
    INT64                 lpmRequestDelta = requestId - pMultiRequestData->requestID[m_peerPipelineId];
    BOOL                  negate = static_cast<BOOL>(lpmRequestDelta <= 0);
    UINT                SensorTags[] =
    {
        PropertyIDSensorMetaData,
        PropertyIDSensorResolutionInfo
    };
    static const UINT   NumSensorTags = CAMX_ARRAY_SIZE(SensorTags);
    VOID*               pData[NumSensorTags] = { 0 };
    UINT64              offsets[NumSensorTags] =
    {
        static_cast<UINT64>(abs(lpmRequestDelta)),
        static_cast<UINT64>(abs(lpmRequestDelta))
    };

    result = GetDataListFromPipeline(SensorTags, pData, offsets, NumSensorTags, &negate, m_peerPipelineId);

    if ((CamxResultSuccess == result) && (NULL != pData[0]) && (NULL != pData[1]))
    {
        SensorMetaData*       pMasterMetaData       = NULL;
        SensorResolutionInfo* pMasterResoultionInfo = NULL;

        pMasterMetaData       = static_cast<SensorMetaData*>(pData[0]);
        pMasterResoultionInfo = static_cast<SensorResolutionInfo*>(pData[1]);

        if ((NULL != pMasterMetaData) && (NULL != pMasterResoultionInfo))
        {
            FLOAT masterFps = static_cast<FLOAT>(pMasterResoultionInfo->frameLengthLine) /
                              static_cast<FLOAT>(pMasterMetaData->frameLengthLines) *
                              pMasterResoultionInfo->frameRate;

            pSensorParam->currentFrameLengthLines = static_cast<UINT32>(
                static_cast<FLOAT>(GetSensorDataObject()->GetFrameLengthLines(m_currentResolutionIndex)) *
                GetSensorDataObject()->GetMaxFPS(m_currentResolutionIndex) / masterFps);

            CAMX_LOG_VERBOSE(CamxLogGroupSensor,
                             "masterFps: %f, slave FLL:%u, slaveMaxFPS %f, adjusted slave FLL = %u",
                             masterFps,
                             GetSensorDataObject()->GetFrameLengthLines(m_currentResolutionIndex),
                             GetSensorDataObject()->GetMaxFPS(m_currentResolutionIndex),
                             pSensorParam->currentFrameLengthLines);

            if (pSensorParam->currentFrameLengthLines <
                pSensorParam->currentLineCount + GetSensorDataObject()->GetExposureControlInfo()->verticalOffset)
            {
                UINT64 exposureTime = 0;
                FLOAT  gain         = pSensorParam->currentGain;
                UINT   linecount    = pSensorParam->currentFrameLengthLines;

                linecount = pSensorParam->currentFrameLengthLines -
                    GetSensorDataObject()->GetExposureControlInfo()->verticalOffset;
                exposureTime = GetSensorDataObject()->LineCountToExposure(linecount, m_currentResolutionIndex);
                gain = gain * (static_cast<FLOAT>(pSensorParam->currentExposure) / static_cast<FLOAT>(exposureTime));

                if (gain < 1.0)
                {
                    linecount = static_cast<UINT>(static_cast<FLOAT>(linecount) * gain);
                    gain = 1.0;
                }

                if (0 == linecount)
                {
                    linecount = 1;
                }

                pSensorParam->currentExposure  = exposureTime;
                pSensorParam->currentGain      = gain;
                pSensorParam->currentLineCount = linecount;

            }

            CAMX_LOG_VERBOSE(CamxLogGroupSensor, "Update slave exp_info done: cur_fll:%u, exp_time:%llu, lc:%u, gain:%f",
                pSensorParam->currentFrameLengthLines,
                pSensorParam->currentExposure,
                pSensorParam->currentLineCount,
                pSensorParam->currentGain);
        }
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "Get data from peer pipeline:%u failed", m_peerPipelineId);
    }

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SensorNode::GetOTPData
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const EEPROMOTPData* SensorNode::GetOTPData()
{
    CamxResult            result     = CamxResultSuccess;
    const EEPROMOTPData*  pOTPData   = NULL;
    HwCameraInfo          cameraInfo;

    result = HwEnvironment::GetInstance()->GetCameraInfo(m_cameraId, &cameraInfo);

    if (CamxResultSuccess == result)
    {
        pOTPData = &(cameraInfo.pSensorCaps->OTPData);
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "Failed to obtain EEPROM OTP data, result: %d", result);
    }

    return pOTPData;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SensorNode::LoadPDlibrary
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::LoadPDlibrary(
    CHAR* pPDAFLibName)
{
    CamxResult result = CamxResultSuccess;

    if (NULL != pPDAFLibName)
    {
        CAMX_LOG_VERBOSE(CamxLogGroupSensor, "PD library to load %s", pPDAFLibName);
    }

    m_pPDLibHandler = CAMX_NEW CPDLibHandler();

    if (NULL == m_pPDLibHandler)
    {
        return CamxResultENoMemory;
    }

    if (NULL != m_pPDCallback && NULL != m_pPDCallback->pfnSetAlgoInterface)
    {

        /// @todo (CAMX-2931): Add vendor tag support to Pdlib
#if PDLIB_VENDOR_TAG_SUPPORT
        CHIALGORITHMINTERFACE chiAlgoInterface;

        StatsVendorTagCallbacks::GetInstance()->SetMetatadataPool(pFinalizeInitializationData->pMainPool);
        chiAlgoInterface.pGetVendorTagBase = StatsVendorTagCallbacks::GetVendorTagBase;
        chiAlgoInterface.pGetMetadata      = StatsVendorTagCallbacks::GetVendorTag;
        chiAlgoInterface.pSetMetaData      = StatsVendorTagCallbacks::SetVendorTag;
        m_pPDCallback->pfnSetAlgoInterface(&chiAlgoInterface);
#endif // PDLIB_VENDOR_TAG_SUPPORT

        // Create an instance of the PD library
        result = m_pPDLibHandler->CreateLib(m_pPDCallback->pfnCreate, &m_pPDLib, pPDAFLibName, m_cameraId);
        CAMX_ASSERT(m_pPDLib != NULL);
        CAMX_ASSERT(CamxResultSuccess == result);
    }

    UINTPTR_T PDLibAddr             = reinterpret_cast<UINTPTR_T>(m_pPDLib);
    const UINT SensorPDOutputTags[] = { PropertyIDUsecasePDLibInfo };
    const VOID* pPDOutputData[1]    = { 0 };
    UINT pPDDataCount[1]            = { 0 };
    pPDDataCount[0]                 = sizeof(PDLibAddr);
    pPDOutputData[0]                = &PDLibAddr;
    WriteDataList(SensorPDOutputTags, pPDOutputData, pPDDataCount, 1);

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SensorNode::ProcessingNodeFinalizeInitialization
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::ProcessingNodeFinalizeInitialization(
    FinalizeInitializationData* pFinalizeInitializationData)
{
    CamxResult              result           = CamxResultSuccess;
    CSLCSIPHYCapability     CSIPHYCapability = {0};
    CSLFlashQueryCapability flashCapability  = {0};
    CSLActuatorCapability   actuatorCap      = {0};
    CSLOISCapability        oisCap           = {0};
    ResolutionData*         pResolutionData  = NULL;

    ///@ note 0 is the type for Sensor
    CAMX_ASSERT_MESSAGE(Sensor == Type(), "Invalid type: %d", Type());
    CAMX_ASSERT(NULL != GetHwContext());

    m_pHwContext        = GetHwContext();
    m_cameraId          = GetPipeline()->GetCameraId();

    HwEnvironment::GetInstance()->InitializeSensorHwDeviceCache(m_cameraId,
        GetHwContext(), m_pSensorSubDevicesCache->GetSensorSubDeviceHandles(m_cameraId),
        m_pSensorSubDevicesCache);

    m_currentSyncMode   = GetPipeline()->GetSyncMode();
    m_pThreadManager    = pFinalizeInitializationData->pThreadManager;
    CAMX_LOG_INFO(CamxLogGroupSensor, "CameraID:%d Sensor Sync Mode:%d" , m_cameraId, m_currentSyncMode);

    CAMX_ASSERT_MESSAGE(m_cameraId < MaxNumImageSensors, "Invalid camera ID: %d", m_cameraId);

    if ((NULL != m_pHwContext) && (m_cameraId < MaxNumImageSensors))
    {
        // NOWHINE CP036a: Need exception here
        m_pSensorModuleData = const_cast<ImageSensorModuleData*>(m_pHwContext->GetImageSensorModuleData(m_cameraId));

        CAMX_ASSERT(NULL != m_pSensorModuleData);

        if (NULL != m_pSensorModuleData)
        {
            result = GetSensorModuleIndexes(&CSIPHYCapability, &flashCapability, &actuatorCap, &oisCap);
        }

        if (CamxResultSuccess != result)
        {
            return result;
        }

        // Reload EEPROM data before publishing when the below property is set to 1
        if (TRUE == OsUtils::GetPropertyBool("persist.vendor.camera.eeprom.reload", FALSE))
        {
            CAMX_LOG_INFO(CamxLogGroupSensor, "Reloading EEPROM data");
            HwEnvironment::GetInstance()->ReadEEPROMData(m_cameraId, m_pHwContext->GetCSLSession());
        }

        if (TRUE == GetStaticSettings()->dumpSensorEEPROMData)
        {
            HwEnvironment::GetInstance()->DumpEEPROMData(m_cameraId);
        }
    }

    // Determine current sensor mode before published to usecase property pool
    m_pCurrentSensorModeInfo = pFinalizeInitializationData->pSensorModeInfo;
    m_currentResolutionIndex = pFinalizeInitializationData->pSensorModeInfo->modeIndex;

    const CSIInformation*   pCSIInfo        = NULL;
    UsecaseSensorModes      sensorModeData  = { { {0} } };
    BOOL                    isComboMode     = FALSE;

    if (NULL != m_pSensorModuleData)
    {
        pCSIInfo = m_pSensorModuleData->GetCSIInfo();
    }

    if (NULL != pCSIInfo)
    {
        isComboMode = pCSIInfo->isComboMode;
    }

    GetSensorDataObject()->PopulateSensorModeData(&sensorModeData, CSIPHYCapability.slotInfo, isComboMode);

    UINT           metaTag        = 0;

    // Update the OTP data member variable and here on this can be used wherever OTP data info is needed.
    // Do not move this to earlier as this should get the updated data when reload is enabled
    m_pOTPData = GetOTPData();

    if (NULL == m_pOTPData)
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "OTP data is NULL");
        return CamxResultEInvalidPointer;
    }

    m_opt_wb_grgb = m_pOTPData->WBCalibration[0].grOverGB;
    pResolutionData  = &(GetSensorDataObject()->GetResolutionInfo())->resolutionData[m_currentResolutionIndex];

    // Setup what we are going to publish since we know it in advance
    UINT SensorOutputTags[] =
    {
        PropertyIDUsecaseSensorModes,
        PropertyIDUsecaseSensorCurrentMode,
        0,
        0
    };

    static const UINT NumSensorMetaDataTags             = CAMX_ARRAY_SIZE(SensorOutputTags);
    const VOID*       pData[NumSensorMetaDataTags]      = { 0 };
    UINT              pDataCount[NumSensorMetaDataTags] = { 0 };
    UINT              dataIndex                         = 0;

    pData[dataIndex]        = &sensorModeData;
    pDataCount[dataIndex++] = sizeof(UsecaseSensorModes);

    pData[dataIndex]        = &m_currentResolutionIndex;
    pDataCount[dataIndex++] = sizeof(m_currentResolutionIndex);

    result = VendorTagManager::QueryVendorTagLocation("org.codeaurora.qcamera3.sensor_meta_data",
                                                      "EEPROMInformation",
                                                      &metaTag);
    CAMX_ASSERT_MESSAGE(CamxResultSuccess == result, "Failed to get vendor tag for EEPROMInfo");

    SensorOutputTags[dataIndex] = (metaTag | StaticMetadataSectionMask);
    pData[dataIndex]            = &(m_pOTPData->EEPROMInfo);
    pDataCount[dataIndex++]     = sizeof(EEPROMInformation);

    result = VendorTagManager::QueryVendorTagLocation("org.codeaurora.qcamera3.sensor_meta_data",
                                                      "current_mode",
                                                      &metaTag);
    CAMX_ASSERT_MESSAGE(CamxResultSuccess == result, "Failed to get vendor tag for current_mode");

    SensorOutputTags[dataIndex] = (metaTag | UsecaseMetadataSectionMask);
    pData[dataIndex]            = &m_currentResolutionIndex;
    pDataCount[dataIndex++]     = 1;

    WriteDataList(SensorOutputTags, pData, pDataCount, NumSensorMetaDataTags);

    if (TRUE == pResolutionData->integrationInfoExists)
    {
        UINT        IntegrationInfoTags[]           = { 0 };
        const VOID* pIntegrationInfoData[1]         = { 0 };
        UINT        pIntegrationInfoDataCount[1]    = { 0 };
        UINT        integrationInfoMetaTag          = 0;

        result = VendorTagManager::QueryVendorTagLocation("org.codeaurora.qcamera3.sensor_meta_data",
                                                          "integration_information",
                                                          &integrationInfoMetaTag);
        CAMX_ASSERT_MESSAGE(CamxResultSuccess == result, "Failed to get vendor tag: integration_information");

        IntegrationInfoTags[0]  = integrationInfoMetaTag;
        pIntegrationInfoData[0]                = &pResolutionData->integrationInfo;
        pIntegrationInfoDataCount[0]           = sizeof(IntegrationInformation) / sizeof(UINT32);
        WriteDataList(IntegrationInfoTags, pIntegrationInfoData, pIntegrationInfoDataCount, 1);
    }
    else
    {
        CAMX_LOG_VERBOSE(CamxLogGroupSensor, "IntegrationInfo from sensor bin is not available");
    }

    if ((CamxResultSuccess == result) && (FALSE == GetStaticSettings()->disablePDAF))
    {
        m_isPDAFEnabled = IsPDAFEnabled();

        // ok to fail in cases where pdlibrary does not exist.
        // We log error in the function
        if ((TRUE == m_isPDAFEnabled) && (NULL != m_pSensorModuleData))
        {
            PDAFData* pPDAFData = m_pSensorModuleData->GetPDAFDataObj();
            PopulatePDAFInformation();
            PublishPDAFInformation();
            LoadPDlibrary(pPDAFData->GetPDAFConfigData()->PDInfo.PDAFLibraryName);
        }
    }

    m_updateCmdCount = (4 * (GetPipeline()->GetRequestQueueDepth() + 2));    // 2 extra for meet max request depth

    if ((CamxResultSuccess == result) && (InvalidJobHandle == m_hJobFamilyHandle) && (NULL != m_pSensorModuleData))
    {
        const CHAR* pSensorName = m_pSensorModuleData->GetSensorDataObject()->GetSensorName();
        result = m_pThreadManager->RegisterJobFamily(SensorThreadJobCallback,
                                                     pSensorName,
                                                     NULL,
                                                     JobPriority::High,
                                                     TRUE,
                                                     &m_hJobFamilyHandle);
    }

    if ((CamxResultSuccess == result) && (InvalidJobHandle == m_hJobFamilySubModuleOISHandle) && (NULL != m_pSensorModuleData))
    {
        CHAR OISJobName[256];
        OsUtils::SNPrintF(OISJobName, sizeof(OISJobName), "%s_%s",
            m_pSensorModuleData->GetSensorDataObject()->GetSensorName(), "OIS");
        result = m_pThreadManager->RegisterJobFamily(SensorThreadJobCallback,
                                                     OISJobName,
                                                     NULL,
                                                     JobPriority::High,
                                                     TRUE,
                                                     &m_hJobFamilySubModuleOISHandle);
    }

    if (CamxResultSuccess == result)
    {
        CreateSensorStateSignals();
    }

    if (CamxResultSuccess == result)
    {
        // Must initialize before creating command buffers
        result = InitializeCmdBufferManagerList(SensorMaxCmdBufferManagerCount);
    }

    const StaticSettings* pStaticSettings = GetStaticSettings();
    CAMX_ASSERT(pStaticSettings != NULL);

    if ((CamxResultSuccess == result) &&
        (TRUE == pStaticSettings->enableOISOptimization))
    {
        // OIS initialization:
        // This runs in an offloaded thread parallel to sensor initialization since this is
        // not dependent on the sensor configuration status.
        CAMX_LOG_INFO(CamxLogGroupSensor, "OIS Optimization Enabled");
        SensorPostJob* pSensorPostJob    = CAMX_NEW SensorPostJob;
        if (pSensorPostJob != NULL)
        {
            pSensorPostJob->pSensor = this;
            pSensorPostJob->sensorJobCommand = SensorPostJobCommand::InitializeOIS;
        }
        VOID* pSensorPostJobData[]       = { pSensorPostJob, NULL };
        result                           = m_pThreadManager->PostJob(m_hJobFamilySubModuleOISHandle,
                                                                     NULL,
                                                                     &pSensorPostJobData[0],
                                                                     FALSE,
                                                                     FALSE);
    }

    // Acquire Sensor device
    if (CamxResultSuccess == result)
    {
        result = AcquireDevice();
    }

    if (CamxResultSuccess == result)
    {
        SensorPostJob* pSensorPostJob    = CAMX_NEW SensorPostJob;
        pSensorPostJob->pSensor          = this;
        pSensorPostJob->sensorJobCommand = SensorPostJobCommand::InitializeSensor;
        VOID* pSensorPostJobData[]       = { pSensorPostJob, NULL };
        result                           = m_pThreadManager->PostJob(m_hJobFamilyHandle,
                                                                     NULL,
                                                                     &pSensorPostJobData[0],
                                                                     FALSE,
                                                                     FALSE);
    }

    if (CamxResultSuccess != result)
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "ProcessingNodeFinalize on Sensor failed: %d", CamxResultStrings[result]);
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SensorNode::CreateSensorStateSignals
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::CreateSensorStateSignals()
{
    CamxResult result = CamxResultSuccess;

    m_signalSensorInit.pWaitCondition       = Condition::Create("SensorInitDone");
    m_signalSensorConfig.pWaitCondition     = Condition::Create("SensorConfigDone");
    m_signalSensorSubModules.pWaitCondition = Condition::Create("SensorSubModuleCreated");
    m_signalSensorInit.pMutex               = Mutex::Create("SensorInitDone");
    m_signalSensorConfig.pMutex             = Mutex::Create("SensorConfigDone");
    m_signalSensorSubModules.pMutex         = Mutex::Create("SensorSubModuleCreated");
    m_signalOISInit.pWaitCondition          = Condition::Create("OISInitDone");
    m_signalOISInit.pMutex                  = Mutex::Create("OISInitDone");

    if ((NULL == m_signalSensorInit.pWaitCondition)       || (NULL == m_signalSensorConfig.pWaitCondition) ||
        (NULL == m_signalSensorSubModules.pWaitCondition) || (NULL == m_signalSensorInit.pMutex) ||
        (NULL == m_signalSensorConfig.pMutex)             || (NULL == m_signalSensorSubModules.pMutex) ||
        (NULL == m_signalOISInit.pWaitCondition)          || (NULL == m_signalOISInit.pMutex))
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "Failed to create sensor state signal");
        result = CamxResultEFailed;
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SensorNode::IsPDAFEnabled
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL SensorNode::IsPDAFEnabled()
{
    BOOL     isSupported = FALSE;
    PDAFType PDType      = PDAFType::PDTypeUnknown;

    m_pSensorModuleData->GetPDAFInformation(m_currentResolutionIndex, &isSupported, &PDType);

    return isSupported;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SensorNode::UpdateStartupExposureSettings
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::UpdateStartupExposureSettings()
{
    CamxResult result             = CamxResultSuccess;
    BOOL       applyShortExposure = FALSE;

    static const UINT UsecaseProperties[] =
    {
        PropertyIDUsecaseAECFrameControl,
    };
    VOID* pUsecaseData[1] = { 0 };
    UINT64 usecaseDataOffset[1] = { 0 };
    UINT length = CAMX_ARRAY_SIZE(UsecaseProperties);

    GetDataList(UsecaseProperties, pUsecaseData, usecaseDataOffset, length);
    if (NULL != pUsecaseData[0])
    {
        AECFrameControl* pControl = reinterpret_cast<AECFrameControl*>(pUsecaseData[0]);
        applyShortExposure = GetSensorDataObject()->IsHDRMode(m_currentResolutionIndex);

        SensorParam updateParam = { 0 };
        UpdateSensorExposure(applyShortExposure, &updateParam, pControl);
        updateParam.pRegControlData = NULL;

        // Second argument can be NULL because we do not need to update slave exposure settings based on the master
        // sensor in the first frame
        PrepareSensorUpdate(&updateParam, NULL);
        CAMX_LOG_VERBOSE(CamxLogGroupSensor,
            "Sensor: Update Startup Exposure: Gain = %f ExpTime = %ld, Short Gain = %f Short ExpTime = %ld FLL = %u",
            updateParam.currentGain,
            updateParam.currentExposure,
            updateParam.currentShortGain,
            updateParam.currentShortExposure,
            updateParam.currentFrameLengthLines);

        m_sensorParam.currentGain             = updateParam.currentGain;
        m_sensorParam.currentExposure         = updateParam.currentExposure;
        m_sensorParam.currentLineCount        = updateParam.currentLineCount;
        m_sensorParam.currentShortGain        = updateParam.currentShortGain;
        m_sensorParam.currentShortExposure    = updateParam.currentShortExposure;
        m_sensorParam.currentShortLineCount   = updateParam.currentShortLineCount;
        m_sensorParam.currentFrameLengthLines = updateParam.currentFrameLengthLines;
    }
    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SensorNode::UpdateLensInformation
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::UpdateLensInformation(
    LensInfo* pLensInfo)
{
    CamxResult result                       = CamxResultSuccess;

    const LensInformation* pLensInformation = m_pSensorModuleData->GetLensInfo();

    if (NULL == pLensInformation)
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "Lens Information is NULL");
        return CamxResultEInvalidPointer;
    }

    pLensInfo->fNumber             = static_cast <FLOAT> (pLensInformation->fNumber);
    pLensInfo->totalFDistance      = static_cast <FLOAT> (pLensInformation->maxFocusDistance);
    pLensInfo->focalLength         = static_cast <FLOAT> (pLensInformation->focalLength);
    pLensInfo->actuatorSensitivity = m_pSensorModuleData->GetActuatorSensitivity();
    pLensInfo->pixelSize           = GetSensorDataObject()->GetPixelSize();

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SensorNode::FinalizeBufferProperties
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID SensorNode::FinalizeBufferProperties(
    BufferNegotiationData* pBufferNegotiationData)
{
    CAMX_UNREFERENCED_PARAM(pBufferNegotiationData);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SensorNode::CreateAndSubmitCommand
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::CreateAndSubmitCommand(
    UINT cmdSize,
    I2CRegSettingType cmdType,
    CSLPacketOpcodesSensor opCode,
    UINT32 currentResolutionIndex,
    UINT regSettingIdx)

{
    CamxResult  result = CamxResultSuccess;

    // Create configuration packet/command buffers
    ResourceParams resourceParams = { 0 };
    resourceParams.usageFlags.packet = 1;
    resourceParams.packetParams.maxNumCmdBuffers = 1;
    resourceParams.packetParams.maxNumIOConfigs = 0;
    resourceParams.resourceSize = Packet::CalculatePacketSize(&resourceParams.packetParams);
    resourceParams.poolSize = resourceParams.resourceSize;
    resourceParams.alignment = CamxPacketAlignmentInBytes;
    resourceParams.pDeviceIndices = NULL;
    resourceParams.numDevices = 0;
    resourceParams.memFlags = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

    result = CreateCmdBufferManager(&resourceParams, &m_pConfigPacketManager);
    if (CamxResultSuccess == result)
    {
        ResourceParams params = { 0 };
        params.resourceSize = cmdSize;
        params.poolSize = InitialConfigCmdCount * cmdSize;
        params.usageFlags.cmdBuffer = 1;
        params.cmdParams.type = CmdType::I2C;
        params.alignment = CamxCommandBufferAlignmentInBytes;
        params.pDeviceIndices = NULL;
        params.numDevices = 0;
        params.memFlags = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

        result = CreateCmdBufferManager(&params, &m_pConfigCmdBufferManager);
    }

    if ((CamxResultSuccess == result) && (NULL != m_pConfigCmdBufferManager) && (NULL != m_pConfigPacketManager))
    {
        m_pConfigCmdBuffer = GetCmdBuffer(m_pConfigCmdBufferManager);
        m_pConfigPacket = GetPacket(m_pConfigPacketManager);

        if ((NULL == m_pConfigPacket) || (NULL == m_pConfigCmdBuffer))
        {
            result = CamxResultENoMemory;
        }
        else
        {
            ImageSensorData* pSensorData = GetSensorDataObject();
            CAMX_ASSERT(NULL != pSensorData);

            VOID* pCmd = m_pConfigCmdBuffer->BeginCommands(cmdSize / sizeof(UINT32));
            if (NULL != pCmd)
            {
                if (I2CRegSettingType::AEC == cmdType)
                {
                    result = pSensorData->CreateI2CCmd(cmdType,
                                                       pCmd,
                                                       m_pRegSettings,
                                                       currentResolutionIndex,
                                                       regSettingIdx);
                }
                else if (I2CRegSettingType::SPC == cmdType)
                {
                    result = pSensorData->CreateI2CCmd(cmdType,
                                                       pCmd,
                                                       static_cast<const VOID*>(&m_pOTPData->SPCCalibration.settings),
                                                       currentResolutionIndex,
                                                       regSettingIdx);
                }
                else if (I2CRegSettingType::AWB == cmdType)
                {
                    result = pSensorData->CreateI2CCmd(cmdType,
                                                       pCmd,
                                                       static_cast<const VOID*>(&m_pOTPData->WBCalibration[0].settings),
                                                       currentResolutionIndex,
                                                       regSettingIdx);
                }
                else if (I2CRegSettingType::LSC == cmdType)
                {
                    result = pSensorData->CreateI2CCmd(cmdType,
                                                       pCmd,
                                                       static_cast<const VOID*>(&m_pOTPData->LSCCalibration[0].settings),
                                                       currentResolutionIndex,
                                                       regSettingIdx);
                }
                else
                {
                    result = pSensorData->CreateI2CCmd(cmdType, pCmd, NULL, currentResolutionIndex, regSettingIdx);
                }
                if (CamxResultSuccess == result)
                {
                    result = m_pConfigCmdBuffer->CommitCommands();
                }
            }
            if (CamxResultSuccess == result)
            {
                // Not associated with any request. Won't be recycled.
                m_pConfigCmdBuffer->SetRequestId(CamxInvalidRequestId);

                // Not associated with any request. Won't be recycled.
                m_pConfigPacket->SetRequestId(CamxInvalidRequestId);

                m_pConfigPacket->SetOpcode(CSLDeviceTypeInvalidDevice, opCode);

                result = m_pConfigPacket->AddCmdBufferReference(m_pConfigCmdBuffer, NULL);
            }

            if (CamxResultSuccess == result)
            {
                result = m_pConfigPacket->CommitPacket();
            }
            if (CamxResultSuccess == result)
            {
                CAMX_LOG_VERBOSE(CamxLogGroupSensor, "IN Submit!");
                // Send Sensor  configuration
                result = m_pHwContext->Submit(m_hSensorDevice, m_pConfigPacket);
                CAMX_LOG_VERBOSE(CamxLogGroupSensor, "out Submit! result %d", result);
            }
            if (NULL != m_pConfigPacketManager)
            {
                m_pConfigPacketManager->Recycle(m_pConfigPacket);
                m_pConfigPacket = NULL;
            }

            if (NULL != m_pConfigCmdBufferManager)
            {
                m_pConfigCmdBufferManager->Recycle(m_pConfigCmdBuffer);
                m_pConfigCmdBuffer = NULL;
            }
        }
    }
    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::LoadSensorConfigCmds
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::LoadSensorConfigCmds()
{
    CamxResult       result      = CamxResultEFailed;
    ImageSensorData* pSensorData = GetSensorDataObject();

    CAMX_ASSERT(NULL != pSensorData);

    if (SensorConfigurationStatus::SensorInitializationComplete == m_sensorConfigStatus)
    {
        m_sensorConfigStatus = SensorConfigurationStatus::SensorConfigurationInProgress;
        UINT regSettingIdx = 0; // using common index as only init reg setting uses this param
        UINT resCmdSize   = pSensorData->GetI2CCmdSize(I2CRegSettingType::Res, NULL, m_currentResolutionIndex, &regSettingIdx);
        UINT startCmdSize = pSensorData->GetI2CCmdSize(I2CRegSettingType::Start, NULL, 0, &regSettingIdx);
        UINT stopCmdSize  = pSensorData->GetI2CCmdSize(I2CRegSettingType::Stop, NULL, 0, &regSettingIdx);

        UINT SPCCmdSize                  = 0;
        UINT syncCmdSize                 = 0;

        I2CRegSettingType syncI2CCmdType = I2CRegSettingType::Master;

        if (MasterMode == m_currentSyncMode)
        {
            syncCmdSize    = pSensorData->GetI2CCmdSize(I2CRegSettingType::Master, NULL, 0, &regSettingIdx);
            syncI2CCmdType = I2CRegSettingType::Master;
        }
        else if (SlaveMode == m_currentSyncMode)
        {
            syncCmdSize    = pSensorData->GetI2CCmdSize(I2CRegSettingType::Slave, NULL, 0, &regSettingIdx);
            syncI2CCmdType = I2CRegSettingType::Slave;
        }

        if ((NULL != m_pOTPData) && (TRUE == m_pOTPData->SPCCalibration.isAvailable))
        {
            SPCCmdSize = pSensorData->GetI2CCmdSize(I2CRegSettingType::SPC,
                                                    static_cast<const VOID*>(&m_pOTPData->SPCCalibration.settings),
                                                    0, &regSettingIdx);
        }

        CAMX_ASSERT_MESSAGE((resCmdSize != 0) && (startCmdSize != 0) && (stopCmdSize != 0),
            "Command size(res: %d, start: %d stop: %d)", resCmdSize, startCmdSize, stopCmdSize);

        // All sizes should be a multiple of dword
        CAMX_ASSERT(0 == (resCmdSize % sizeof(UINT32)));
        CAMX_ASSERT(0 == (startCmdSize % sizeof(UINT32)));
        CAMX_ASSERT(0 == (stopCmdSize % sizeof(UINT32)));

        if ((NULL != m_pOTPData) && (TRUE == m_pOTPData->SPCCalibration.isAvailable))
        {
            CAMX_ASSERT(0 == (SPCCmdSize % sizeof(UINT32)));
        }

        CAMX_LOG_INFO(CamxLogGroupSensor,
            "resCmdSize: %d, startCmdSize: %d, stopCmdSize:= %d, syncCmdSize: %d, SPCCmdSize: %d",
            resCmdSize, startCmdSize, stopCmdSize, syncCmdSize, SPCCmdSize);

        result = CreateAndSubmitCommand(
            resCmdSize, I2CRegSettingType::Res, CSLPacketOpcodesSensorConfig,
            m_currentResolutionIndex, regSettingIdx);

        if (CamxResultSuccess == result)
        {
            CAMX_LOG_VERBOSE(CamxLogGroupSensor, "Res configuration successful!");

            if (NoSync != m_currentSyncMode)
            {
                if (0 == syncCmdSize)
                {
                    CAMX_LOG_WARN(CamxLogGroupSensor,
                        "Seems no sensor sync setting in sensor driver, can't apply sync setting!");
                }
                else
                {
                    result = CreateAndSubmitCommand(syncCmdSize, syncI2CCmdType,
                             CSLPacketOpcodesSensorConfig, 0, regSettingIdx);

                    if (CamxResultSuccess == result)
                    {
                        CAMX_LOG_INFO(CamxLogGroupSensor, "Sensor hardware sync configure successful!");
                    }
                    else
                    {
                        CAMX_LOG_ERROR(CamxLogGroupSensor, "Sensor hardware sync configure failed!");
                    }
                }
            }

            if ((CamxResultSuccess == result) && (0 != SPCCmdSize))
            {
                result = CreateAndSubmitCommand(SPCCmdSize, I2CRegSettingType::SPC,
                         CSLPacketOpcodesSensorConfig, 0, regSettingIdx);
                if (CamxResultSuccess == result)
                {
                    CAMX_LOG_VERBOSE(CamxLogGroupSensor, "SpcSetting configuration successful!");
                }
                else
                {
                    CAMX_LOG_ERROR(CamxLogGroupSensor, "SpcSetting configuration failed!");
                }
            }

            if (CamxResultSuccess == result)
            {
                result = CreateAndSubmitCommand(startCmdSize, I2CRegSettingType::Start,
                         CSLPacketOpcodesSensorStreamOn, 0, regSettingIdx);

                if (CamxResultSuccess == result)
                {
                    CAMX_LOG_VERBOSE(CamxLogGroupSensor, "Streamon configuration successful!");

                    result = CreateAndSubmitCommand(stopCmdSize, I2CRegSettingType::Stop,
                             CSLPacketOpcodesSensorStreamOff, 0, regSettingIdx);

                    if (CamxResultSuccess == result)
                    {
                        CAMX_LOG_VERBOSE(CamxLogGroupSensor, "StreamOFF configuration successful!");
                    }
                    else
                    {
                        CAMX_LOG_ERROR(CamxLogGroupSensor, "Sensor Streamoff configuration failed!");
                    }
                }
                else
                {
                    CAMX_LOG_ERROR(CamxLogGroupSensor, "Sensor StreamOn configuration failed!");
                }
            }
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Sensor Res configuration failed!");
        }
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "Sensor Initialization failed, cannot configure sensor!");
    }

    if (CamxResultSuccess == result)
    {
        m_sensorConfigStatus = SensorConfigurationStatus::SensorConfigurationComplete;
        CAMX_LOG_INFO(CamxLogGroupSensor, "Sensor configuration successful");
    }
    else
    {
        m_sensorConfigStatus = SensorConfigurationStatus::SensorConfigurationFailed;
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::CreateActuatorResources()
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::CreateActuatorResources()
{
    CamxResult     result               = CamxResultSuccess;
    ResourceParams packetResourceParams = {0};
    ResourceParams cmdResourceParams    = {0};
    UINT           I2CInfoCmdSize       = sizeof(CSLSensorI2CInfo);
    UINT           powerUpCmdSize       = m_pSensorModuleData->GetActuatorDataObject()->GetPowerSequenceCmdSize(TRUE);
    UINT           powerDownCmdSize     = m_pSensorModuleData->GetActuatorDataObject()->GetPowerSequenceCmdSize(FALSE);
    UINT           powerSequenceSize    = (powerUpCmdSize + powerDownCmdSize);
    UINT           initializeCmdSize    = m_pSensorModuleData->GetActuatorDataObject()->GetInitializeCmdSize();

    if (CamxResultSuccess == result)
    {
        packetResourceParams.usageFlags.packet             = 1;
        // one for power sequence, one for I2C Info, one for init settings - Total 3 cmd buffers
        packetResourceParams.packetParams.maxNumCmdBuffers = 3;
        packetResourceParams.packetParams.maxNumIOConfigs  = 0;
        packetResourceParams.resourceSize                  =
            Packet::CalculatePacketSize(&packetResourceParams.packetParams);
        packetResourceParams.poolSize                      = packetResourceParams.resourceSize;
        packetResourceParams.alignment                     = CamxPacketAlignmentInBytes;
        packetResourceParams.pDeviceIndices                = NULL;
        packetResourceParams.numDevices                    = 0;
        packetResourceParams.memFlags                      = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

        result = CreateCmdBufferManager(&packetResourceParams, &m_pActuatorInitializePacketManager);
    }

    if (CamxResultSuccess == result)
    {
        cmdResourceParams.resourceSize         = I2CInfoCmdSize;
        cmdResourceParams.poolSize             = I2CInfoCmdCount * I2CInfoCmdSize;
        cmdResourceParams.usageFlags.cmdBuffer = 1;
        cmdResourceParams.cmdParams.type       = CmdType::Generic;
        cmdResourceParams.alignment            = CamxCommandBufferAlignmentInBytes;
        cmdResourceParams.pDeviceIndices       = NULL;
        cmdResourceParams.numDevices           = 0;
        cmdResourceParams.memFlags             = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

        result = CreateCmdBufferManager(&cmdResourceParams, &m_pActuatorI2CInfoCmdManager);
    }

    if (CamxResultSuccess == result)
    {
        ResourceParams cmdResourceParams    = {0};

        cmdResourceParams.resourceSize         = powerSequenceSize;
        cmdResourceParams.poolSize             = cmdResourceParams.resourceSize;
        cmdResourceParams.usageFlags.cmdBuffer = 1;
        cmdResourceParams.cmdParams.type       = CmdType::Generic;
        cmdResourceParams.alignment            = CamxCommandBufferAlignmentInBytes;
        cmdResourceParams.pDeviceIndices       = NULL;
        cmdResourceParams.numDevices           = 0;
        cmdResourceParams.memFlags             = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

        result = CreateCmdBufferManager(&cmdResourceParams, &m_pActuatorPowerCmdManager);
    }

    if (CamxResultSuccess == result)
    {
        cmdResourceParams.resourceSize         = initializeCmdSize;
        cmdResourceParams.poolSize             = InitialConfigCmdCount * initializeCmdSize;
        cmdResourceParams.usageFlags.cmdBuffer = 1;
        cmdResourceParams.cmdParams.type       = CmdType::I2C;
        cmdResourceParams.alignment            = CamxCommandBufferAlignmentInBytes;
        cmdResourceParams.pDeviceIndices       = NULL;
        cmdResourceParams.numDevices           = 0;
        cmdResourceParams.memFlags             = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

        result = CreateCmdBufferManager(&cmdResourceParams, &m_pActuatorInitializeCmdManager);
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::CreateFlashResources()
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::CreateFlashResources()
{
    CamxResult        result                     = CamxResultSuccess;
    CmdBufferManager* pFlashPacketManager        = NULL;
    CmdBufferManager* pFlashInitializeCmdManager = NULL;
    CmdBufferManager* pFlashFireCmdManager       = NULL;
    CmdBufferManager* pFlashRERCmdManager        = NULL;
    CmdBufferManager* pFlashQueryCmdManager      = NULL;
    UINT              maxRequestQueueDepth       = GetPipeline()->GetRequestQueueDepth() + 2;

    ResourceParams packetResourceParams = {0};

    packetResourceParams.usageFlags.packet             = 1;
    packetResourceParams.packetParams.maxNumCmdBuffers = FlashCmdCount;
    packetResourceParams.packetParams.maxNumIOConfigs  = 0;
    packetResourceParams.packetParams.maxNumPatches    = 0;
    packetResourceParams.resourceSize                  = Packet::CalculatePacketSize(&packetResourceParams.packetParams);
    packetResourceParams.poolSize                      =
        (FlashCmdCount * (maxRequestQueueDepth * packetResourceParams.resourceSize));
    packetResourceParams.alignment                     = CamxPacketAlignmentInBytes;
    packetResourceParams.pDeviceIndices                = NULL;
    packetResourceParams.numDevices                    = 0;
    packetResourceParams.memFlags                      = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

    result = CreateCmdBufferManager(&packetResourceParams, &pFlashPacketManager);

    if (CamxResultSuccess != result)
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "Fail to create FlashPacketManager, result %d", result);
    }

    if (CamxResultSuccess == result)
    {
        ResourceParams cmdResourceParams = {0};

        cmdResourceParams.resourceSize         = sizeof(CSLFlashInfoCmd);
        cmdResourceParams.poolSize             = (maxRequestQueueDepth * cmdResourceParams.resourceSize);
        cmdResourceParams.usageFlags.cmdBuffer = 1;
        cmdResourceParams.cmdParams.type       = CmdType::Generic;
        cmdResourceParams.alignment            = CamxCommandBufferAlignmentInBytes;
        cmdResourceParams.pDeviceIndices       = NULL;
        cmdResourceParams.numDevices           = 0;
        cmdResourceParams.memFlags             = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

        result = CreateCmdBufferManager(&cmdResourceParams, &pFlashInitializeCmdManager);
        if (CamxResultSuccess != result)
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Fail to create FlashInitializeCmdManager, result %d", result);
        }
    }


    if (CamxResultSuccess == result)
    {
        ResourceParams cmdResourceParams = {0};

        cmdResourceParams.resourceSize         = sizeof(CSLFlashFireCmd);
        cmdResourceParams.poolSize             = (maxRequestQueueDepth * cmdResourceParams.resourceSize);
        cmdResourceParams.usageFlags.cmdBuffer = 1;
        cmdResourceParams.cmdParams.type       = CmdType::Generic;
        cmdResourceParams.alignment            = CamxCommandBufferAlignmentInBytes;
        cmdResourceParams.pDeviceIndices       = NULL;
        cmdResourceParams.numDevices           = 0;
        cmdResourceParams.memFlags             = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

        result = CreateCmdBufferManager(&cmdResourceParams, &pFlashFireCmdManager);
        if (CamxResultSuccess != result)
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Fail to create FlashFireCmdManager, result %d", result);
        }
    }

    if (CamxResultSuccess == result)
    {
        ResourceParams cmdResourceParams = {0};

        cmdResourceParams.resourceSize         = sizeof(CSLFlashQueryCurrentCmd);;
        cmdResourceParams.poolSize             = (maxRequestQueueDepth * cmdResourceParams.resourceSize);
        cmdResourceParams.usageFlags.cmdBuffer = 1;
        cmdResourceParams.cmdParams.type       = CmdType::Generic;
        cmdResourceParams.alignment            = CamxCommandBufferAlignmentInBytes;
        cmdResourceParams.pDeviceIndices       = NULL;
        cmdResourceParams.numDevices           = 0;
        cmdResourceParams.memFlags             = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

        result = CreateCmdBufferManager(&cmdResourceParams, &pFlashQueryCmdManager);
        if (CamxResultSuccess != result)
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Fail to create FlashQueryCmdManager, result %d", result);
        }
    }

    if (CamxResultSuccess == result)
    {
        ResourceParams cmdResourceParams = {0};

        cmdResourceParams.resourceSize         = sizeof(CSLFlashRERCmd);
        cmdResourceParams.poolSize             = (maxRequestQueueDepth * cmdResourceParams.resourceSize);
        cmdResourceParams.usageFlags.cmdBuffer = 1;
        cmdResourceParams.cmdParams.type       = CmdType::Generic;
        cmdResourceParams.alignment            = CamxCommandBufferAlignmentInBytes;
        cmdResourceParams.pDeviceIndices       =  NULL;
        cmdResourceParams.numDevices           = 0;
        cmdResourceParams.memFlags             = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

        result = CreateCmdBufferManager(&cmdResourceParams, &pFlashRERCmdManager);
        if (CamxResultSuccess != result)
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Fail to create FlashRERCmdManager")
        }
    }

    const StaticSettings* pStaticSettings = GetStaticSettings();
    if ((CamxResultSuccess == result) && (FALSE == pStaticSettings->disableFlash))
    {
        FlashCreateData createData = {0};

        createData.pHwContext            = m_pHwContext;
        createData.pPacketManager        = pFlashPacketManager;
        createData.pInitializeCmdManager = pFlashInitializeCmdManager;
        createData.pFireCmdManager       = pFlashFireCmdManager;
        createData.pRERCmdManager        = pFlashRERCmdManager;
        createData.pQueryCmdManager      = pFlashQueryCmdManager;
        createData.pParentNode           = this;
        createData.cameraId              = m_cameraId;
        createData.operationMode         = CSLRealtimeOperation;

        result = Flash::Create(&createData);
        if (CamxResultSuccess == result)
        {
            m_pFlash = createData.pFlash;
            CAMX_LOG_VERBOSE(CamxLogGroupSensor, "Flash resources initialized");
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Flash resources initialization failed");
        }
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::CreateOisResources()
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::CreateOisResources()
{
    CamxResult        result            = CamxResultSuccess;
    UINT              I2CInfoCmdSize    = sizeof(CSLOISI2CInfo);
    UINT              powerUpCmdSize    = m_pSensorModuleData->GetOisDataObject()->GetPowerSequenceCmdSize(TRUE);
    UINT              powerDownCmdSize  = m_pSensorModuleData->GetOisDataObject()->GetPowerSequenceCmdSize(FALSE);
    UINT              powerSequenceSize = (powerUpCmdSize + powerDownCmdSize);
    UINT              initializeCmdSize = m_pSensorModuleData->GetOisDataObject()->GetInitializeCmdSize();
    UINT              modeCmdSize       = m_pSensorModuleData->GetOisDataObject()->GetOISModeMaxCmdSize();
    SubDeviceProperty oisDevice         = m_pSensorSubDevicesCache->GetSubDevice(m_cameraId, OISHandle);

    if (CamxResultSuccess == result)
    {
        ResourceParams packetResourceParams = {0};

        // Creating 4 command buffers for OIS i2ccmdbuffer, powerSettings, initsettings, calibsettings
        packetResourceParams.usageFlags.packet             = 1;
        packetResourceParams.packetParams.maxNumCmdBuffers = 4;
        packetResourceParams.packetParams.maxNumIOConfigs  = 0;
        packetResourceParams.resourceSize                  =
            Packet::CalculatePacketSize(&packetResourceParams.packetParams);
        packetResourceParams.poolSize                      = packetResourceParams.resourceSize;
        packetResourceParams.alignment                     = CamxPacketAlignmentInBytes;
        packetResourceParams.pDeviceIndices                = NULL;
        packetResourceParams.numDevices                    = 0;
        packetResourceParams.memFlags                      = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

        result = CreateCmdBufferManager(&packetResourceParams, &m_pOISInitializePacketManager);
    }

    if (CamxResultSuccess == result)
    {
        ResourceParams cmdResourceParams    = {0};

        cmdResourceParams.resourceSize         = I2CInfoCmdSize;
        cmdResourceParams.poolSize             = I2CInfoCmdCount * (I2CInfoCmdSize);
        cmdResourceParams.usageFlags.cmdBuffer = 1;
        cmdResourceParams.cmdParams.type       = CmdType::Generic;
        cmdResourceParams.alignment            = CamxCommandBufferAlignmentInBytes;
        cmdResourceParams.pDeviceIndices       = NULL;
        cmdResourceParams.numDevices           = 0;
        cmdResourceParams.memFlags             = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

        result = CreateCmdBufferManager(&cmdResourceParams, &m_pOISI2CInfoCmdManager);
    }

    if (CamxResultSuccess == result)
    {
        ResourceParams cmdResourceParams    = {0};

        cmdResourceParams.resourceSize         = powerSequenceSize;
        cmdResourceParams.poolSize             = cmdResourceParams.resourceSize;
        cmdResourceParams.usageFlags.cmdBuffer = 1;
        cmdResourceParams.cmdParams.type       = CmdType::Generic;
        cmdResourceParams.alignment            = CamxCommandBufferAlignmentInBytes;
        cmdResourceParams.pDeviceIndices       = NULL;
        cmdResourceParams.numDevices           = 0;
        cmdResourceParams.memFlags             = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

        result = CreateCmdBufferManager(&cmdResourceParams, &m_pOISPowerCmdManager);
    }

    if (CamxResultSuccess == result)
    {
        ResourceParams cmdResourceParams    = {0};

        cmdResourceParams.resourceSize         = initializeCmdSize;
        cmdResourceParams.poolSize             = InitialConfigCmdCount* (initializeCmdSize);
        cmdResourceParams.usageFlags.cmdBuffer = 1;
        cmdResourceParams.cmdParams.type       = CmdType::I2C;
        cmdResourceParams.alignment            = CamxCommandBufferAlignmentInBytes;
        cmdResourceParams.pDeviceIndices       = NULL;
        cmdResourceParams.numDevices           = 0;
        cmdResourceParams.memFlags             = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

        result = CreateCmdBufferManager(&cmdResourceParams, &m_pOISInitializeCmdManager);
    }

    if (CamxResultSuccess == result)
    {
        ResourceParams packetResourceParams = {0};

        packetResourceParams.usageFlags.packet             = 1;
        packetResourceParams.packetParams.maxNumCmdBuffers = 1;
        packetResourceParams.packetParams.maxNumIOConfigs  = 0;
        packetResourceParams.resourceSize                  =
            Packet::CalculatePacketSize(&packetResourceParams.packetParams);
        packetResourceParams.poolSize                      = packetResourceParams.resourceSize;
        packetResourceParams.alignment                     = CamxPacketAlignmentInBytes;
        packetResourceParams.pDeviceIndices                = NULL;
        packetResourceParams.numDevices                    = 0;
        packetResourceParams.memFlags                      = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

        result = CreateCmdBufferManager(&packetResourceParams, &m_pOISModePacketManager);
    }

    if (CamxResultSuccess == result)
    {
        ResourceParams cmdResourceParams    = {0};

        cmdResourceParams.resourceSize         = modeCmdSize;
        cmdResourceParams.poolSize             = InitialConfigCmdCount* (modeCmdSize);
        cmdResourceParams.usageFlags.cmdBuffer = 1;
        cmdResourceParams.cmdParams.type       = CmdType::I2C;
        cmdResourceParams.alignment            = CamxCommandBufferAlignmentInBytes;
        cmdResourceParams.pDeviceIndices       = NULL;
        cmdResourceParams.numDevices           = 0;
        cmdResourceParams.memFlags             = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

        result = CreateCmdBufferManager(&cmdResourceParams, &m_pOISModeCmdManager);
    }

    if ((CamxResultSuccess == result) && (NULL != m_pSensorModuleData->GetOisDataObject()))
    {
        OisCreateData createData = {0};

        createData.pHwContext         = m_pHwContext;
        createData.pInitPacketManager = m_pOISInitializePacketManager;
        createData.pInitCmdManager    = m_pOISInitializeCmdManager;
        createData.pI2CInfoCmdManager = m_pOISI2CInfoCmdManager;
        createData.pPowerCmdManager   = m_pOISPowerCmdManager;
        createData.pModeCmdManager    = m_pOISModeCmdManager;
        createData.pModePacketManager = m_pOISModePacketManager;
        createData.cameraId           = m_cameraId;
        createData.pOTPData           = m_pOTPData;
        createData.pParentNode        = this;

        result = OIS::Create(&createData, oisDevice.deviceIndex);

        if (CamxResultSuccess == result)
        {
            m_pOis = createData.pOis;
        }
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::CreatePerFrameUpdateResources
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::CreatePerFrameUpdateResources()
{
    CamxResult result = CamxResultSuccess;

    if (NULL == m_pExposureInfo)
    {
        m_pExposureInfo = static_cast<VOID*>(GetSensorDataObject()->Allocate(SensorAllocateType::ExposureInfo));
    }

    if (NULL == m_pRegSettings)
    {
        m_pRegSettings = static_cast<VOID*>(GetSensorDataObject()->Allocate(SensorAllocateType::I2CRegSetting));
    }

    if (NULL == m_pPDAFSettings)
    {
        m_pPDAFSettings = static_cast<VOID*>(GetSensorDataObject()->Allocate(SensorAllocateType::I2CRegSetting));
    }

    if (NULL == m_pExposureRegAddressInfo)
    {
        m_pExposureRegAddressInfo =
            static_cast<VOID*>(GetSensorDataObject()->Allocate(SensorAllocateType::ExposureRegAddressInfo));

        if (NULL != m_pExposureRegAddressInfo)
        {
            GetSensorDataObject()->UpdateExposureRegAddressInfo(m_pExposureRegAddressInfo);
        }
    }

    if ((NULL == m_pExposureInfo) || (NULL == m_pRegSettings) ||
        (NULL == m_pExposureRegAddressInfo) || (NULL == m_pPDAFSettings))
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor,
                       "Failed to allocate buffer ExposureInfo: %p, RegSettings: %p, RegAddressInfo: %p PDAFsettings =%p",
                       m_pExposureInfo,
                       m_pRegSettings,
                       m_pExposureRegAddressInfo,
                       m_pPDAFSettings);

        return CamxResultEInvalidPointer;
    }

    UINT maxUpdateCmdSize        = GetSensorDataObject()->GetI2CCmdMaxSize(I2CRegSettingType::AEC, m_pRegSettings);
    UINT maxPDAFSettingSize      = GetSensorDataObject()->GetI2CCmdMaxSize(I2CRegSettingType::PDAF, m_pPDAFSettings);
    UINT maxMasterSettingSize    = GetSensorDataObject()->GetI2CCmdMaxSize(I2CRegSettingType::Master, NULL);
    UINT maxSlaveSettingSize     = GetSensorDataObject()->GetI2CCmdMaxSize(I2CRegSettingType::Slave, NULL);

    maxUpdateCmdSize            += maxPDAFSettingSize;
    maxUpdateCmdSize            += maxMasterSettingSize > maxSlaveSettingSize ? maxMasterSettingSize : maxSlaveSettingSize;
    // Update the pdaf setting

    CAMX_LOG_INFO(CamxLogGroupSensor, "maxUpdateCmdSize: %d", maxUpdateCmdSize);

    CAMX_ASSERT(maxUpdateCmdSize != 0);
    CAMX_ASSERT(0 == (maxUpdateCmdSize % sizeof(UINT32)));

    // Create the update packet manager, command manager, packet and commands

    ResourceParams resourceParams                   = { 0 };
    resourceParams.usageFlags.packet                = 1;
    resourceParams.packetParams.maxNumCmdBuffers    = 1;
    resourceParams.packetParams.maxNumIOConfigs     = 0;
    resourceParams.resourceSize                     = Packet::CalculatePacketSize(&resourceParams.packetParams);
    resourceParams.poolSize                         = m_updateCmdCount * resourceParams.resourceSize;
    resourceParams.alignment                        = CamxPacketAlignmentInBytes;
    resourceParams.pDeviceIndices                   = NULL;
    resourceParams.numDevices                       = 0;
    resourceParams.memFlags                         = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

    if (CamxResultSuccess == CreateCmdBufferManager(&resourceParams, &m_pUpdatePacketManager))
    {
        ResourceParams params       = { 0 };
        params.resourceSize         = maxUpdateCmdSize;
        params.poolSize             = m_updateCmdCount * maxUpdateCmdSize;
        params.usageFlags.cmdBuffer = 1;
        params.cmdParams.type       = CmdType::I2C;
        params.alignment            = CamxCommandBufferAlignmentInBytes;
        params.pDeviceIndices       = NULL;
        params.numDevices           = 0;
        params.memFlags             = CSLMemFlagKMDAccess | CSLMemFlagUMDAccess;

        result = CreateCmdBufferManager(&params, &m_pUpdateCmdBufferManager);
    }

    if ((CamxResultSuccess == result) && (NULL != m_pSensorModuleData->GetActuatorDataObject()))
    {
        result = CreateActuatorResources();
    }

    const StaticSettings* pStaticSettings = GetStaticSettings();
    CAMX_ASSERT(pStaticSettings != NULL);

    if ((CamxResultSuccess == result) &&
        (FALSE == pStaticSettings->enableOISOptimization))
    {
        // OIS Optimization is disabled, OIS needs to be created serially now
        result = CreateOISSubmodule();
    }

    if ((CamxResultSuccess == result) &&
        (FALSE == pStaticSettings->disableFlash) &&
        (NULL != m_pSensorModuleData->GetFlashDataObject()))
    {
        result = CreateFlashResources();
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::PrepareSensorUpdate
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID SensorNode::PrepareSensorUpdate(
    SensorParam* pSensorParam,
    NodeProcessRequestData* pNodeProcessRequestData)
{
    VOID*                             pRegControlInfo      = NULL;
    const ExposureContorlInformation* pExposureControlInfo = GetSensorDataObject()->GetExposureControlInfo();
    UINT64                            minExposureTime      =
        static_cast<UINT64>(GetSensorDataObject()->GetLineReadoutTime(m_currentResolutionIndex));

    CAMX_ASSERT(NULL != pExposureControlInfo);

    if ((NULL == m_pExposureInfo) || (NULL == m_pRegSettings) || (NULL == m_pExposureRegAddressInfo))
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor,
                       "Invalid inputs: m_pExposureInfo: %p, m_pRegSettings: %p, RegAddressInfo: %p",
                       m_pExposureInfo,
                       m_pRegSettings,
                       m_pExposureRegAddressInfo);

        return;
    }

    if (pSensorParam->currentExposure < minExposureTime)
    {
        pSensorParam->currentExposure = minExposureTime;
    }
    if (pSensorParam->currentShortExposure < minExposureTime)
    {
        pSensorParam->currentShortExposure = minExposureTime;
    }

    pSensorParam->currentLineCount = GetSensorDataObject()->ExposureToLineCount(pSensorParam->currentExposure,
                                                                                m_currentResolutionIndex);

    pSensorParam->currentShortLineCount = GetSensorDataObject()->ExposureToLineCount(pSensorParam->currentShortExposure,
                                                                                     m_currentResolutionIndex);

    CAMX_LOG_VERBOSE(CamxLogGroupSensor, "AppliedExpTime=%llu", pSensorParam->currentExposure);

    if (pSensorParam->currentLineCount > pExposureControlInfo->maxLineCount)
    {
        pSensorParam->currentLineCount = pExposureControlInfo->maxLineCount;
        /// Updating the actual exposure in case if line count is capped to maxLineCount.
        pSensorParam->currentExposure = GetSensorDataObject()->LineCountToExposure(pSensorParam->currentLineCount,
                                                                                   m_currentResolutionIndex);
    }

    if (pSensorParam->currentShortLineCount > pExposureControlInfo->maxLineCount)
    {
        pSensorParam->currentShortLineCount = pExposureControlInfo->maxLineCount;
        pSensorParam->currentShortExposure = GetSensorDataObject()->LineCountToExposure(pSensorParam->currentShortLineCount,
                                                                                    m_currentResolutionIndex);
    }

    UINT32 frameLengthLines = pSensorParam->currentFrameLengthLines;
    frameLengthLines = static_cast<UINT32>(Utils::RoundDOUBLE(frameLengthLines * GetFpsDiv()));

    if ((TRUE == GetStaticSettings()->enableSensorFpsMatch) && (TRUE == m_isMultiCameraUsecase) &&
        (FALSE == m_isMasterCamera) && (NULL != pNodeProcessRequestData))
    {
        pSensorParam->currentFrameLengthLines = frameLengthLines;
        AdjustSlaveCameraExposureInfo(pSensorParam, pNodeProcessRequestData);
        frameLengthLines = pSensorParam->currentFrameLengthLines;
    }

    /// Make sure that minumum of vertical offset is maintained between line count and frame length lines
    if (pSensorParam->currentLineCount > (frameLengthLines - pExposureControlInfo->verticalOffset))
    {
        frameLengthLines = pSensorParam->currentLineCount + pExposureControlInfo->verticalOffset;
    }
    pSensorParam->currentFrameLengthLines = frameLengthLines;

    GetSensorDataObject()->CalculateExposure(pSensorParam->currentGain,
                                             pSensorParam->currentLineCount,
                                             pSensorParam->currentShortGain,
                                             pSensorParam->currentShortLineCount,
                                             m_pExposureInfo);

    if (NULL != pSensorParam->pRegControlData)
    {
        pRegControlInfo = reinterpret_cast<VOID*>(pSensorParam->pRegControlData->sensorControl.registerControl);
    }

    GetSensorDataObject()->FillExposureArray(m_pExposureInfo,
                                             frameLengthLines,
                                             pRegControlInfo,
                                             m_pExposureRegAddressInfo,
                                             m_pRegSettings,
                                             GetSensorDataObject()->IsHDRMode(m_currentResolutionIndex));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::PrepareSensorPDAFUpdate
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID SensorNode::PrepareSensorPDAFUpdate(
    PDLibWindowConfig* pPDAFWindowConfig)
{
    ResolutionData* pResolutionData = &(GetSensorDataObject()->GetResolutionInfo())->resolutionData[m_currentResolutionIndex];
    UINT sensorWidth                = pResolutionData->streamInfo.streamConfiguration[0].frameDimension.width;
    UINT sensorHeight               = pResolutionData->streamInfo.streamConfiguration[0].frameDimension.height;

    CAMX_ASSERT(NULL != m_pPDAFSettings);

    // PDAF window mode fixed, default, floating support to be added later
    // now configuring only to fixed window
    m_sensorPdafData.PDAFWindowMode        = 0;
    m_sensorPdafData.PDAFroiType           = pPDAFWindowConfig->roiType;
    m_sensorPdafData.PDAFstartX            = static_cast<UINT>((pPDAFWindowConfig->fixedAFWindow.startX) * sensorWidth);
    m_sensorPdafData.PDAFstartY            = static_cast<UINT>((pPDAFWindowConfig->fixedAFWindow.startY) * sensorHeight);
    m_sensorPdafData.PDAFendX              = static_cast<UINT>((pPDAFWindowConfig->fixedAFWindow.endX) * sensorWidth);
    m_sensorPdafData.PDAFendY              = static_cast<UINT>((pPDAFWindowConfig->fixedAFWindow.endY) *sensorHeight);
    m_sensorPdafData.horizontalWindowCount = pPDAFWindowConfig->horizontalWindowCount;
    m_sensorPdafData.verticalWindowCount   = pPDAFWindowConfig->verticalWindowCount;

    if (NULL != m_pPDAFSettings)
    {
        m_isPdafUpdated = GetSensorDataObject()->FillPDAFArray(&m_sensorPdafData, m_pPDAFSettings);
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "m_pPDAFSettings not Available");
    }

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::ApplySensorUpdate
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::ApplySensorUpdate(
    UINT64  requestId)
{
    CamxResult              result                  = CamxResultSuccess;
    BOOL                    isNeedUpdateAEC         = FALSE;
    BOOL                    isNeedUpdateSyncMode    = FALSE;
    BOOL                    isNeedUpdatePDAF        = FALSE;
    VOID*                   pSyncMode               = NULL;
    SensorSyncMode          syncMode                = NoSync;
    MetadataPool*           pPool                   = GetPerFramePool(PoolType::PerFrameInput);
    MetadataSlot*           pSlot                   = pPool->GetSlot(requestId);
    CSLPacketOpcodesSensor  opcode;

    CAMX_ASSERT(NULL != pSlot);
    if ((NULL == m_pUpdatePacketManager) || (NULL == m_pUpdateCmdBufferManager) || (NULL == m_pRegSettings))
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor,
                       "Invalid input(s): packetManager: %p, cmdbufferManager: %p, RegSettings: %p",
                       m_pUpdatePacketManager,
                       m_pUpdateCmdBufferManager,
                       m_pRegSettings);

        return CamxResultEInvalidPointer;
    }

    CAMX_LOG_VERBOSE(CamxLogGroupSensor,
                     "ReqId=%llu gain: %f, lineCount: %u, shortGain: %f, shortLinecount: %u, FLL: %u",
                     requestId,
                     m_sensorParam.currentGain,
                     m_sensorParam.currentLineCount,
                     m_sensorParam.currentShortGain,
                     m_sensorParam.currentShortLineCount,
                     m_sensorParam.currentFrameLengthLines);

    CAMX_LOG_VERBOSE(CamxLogGroupSensor,
        "ReqId=%llu previousGain: %f, previousLineCount: %u, previousFLL:%u",
        requestId,
        m_sensorParam.previousGain,
        m_sensorParam.previousLineCount,
        m_sensorParam.previousFrameLengthLines);

    m_pUpdatePacket = GetPacketForRequest(requestId, m_pUpdatePacketManager);
    m_pUpdateCmds   = GetCmdBufferForRequest(requestId, m_pUpdateCmdBufferManager);

    CAMX_ASSERT(NULL != m_pUpdatePacket);
    CAMX_ASSERT(NULL != m_pUpdateCmds);

    if ((NULL == m_pUpdatePacket) || (NULL == m_pUpdateCmds))
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "NULL input packet or command buffer!");
        return CamxResultENoMemory;
    }

    const StaticSettings* pStaticSettings = GetStaticSettings();
    CAMX_ASSERT(pStaticSettings != NULL);

    if ((pStaticSettings->enableSensorHWSync) && (0 == m_sensorSyncTag))
    {
        result = VendorTagManager::QueryVendorTagLocation("com.qti.chi.multicamerasensorconfig",
            "sensorsyncmodeconfig", &m_sensorSyncTag);
        if (CamxResultSuccess != result)
        {
            CAMX_LOG_WARN(CamxLogGroupSensor, "didn't find sensor sync mode config meta tag");
            m_sensorSyncTag = 0;
            result = CamxResultSuccess;
        }
    }

    syncMode = m_currentSyncMode;
    if ((pStaticSettings->enableSensorHWSync) && (0 != m_sensorSyncTag))
    {
        SensorSyncModeMetadata* pSensorSyncMeta = NULL;
        pSlot->ReadLock();
        pSlot->GetMetadataByTag(m_sensorSyncTag, &pSyncMode);
        if (pSyncMode != NULL)
        {
            pSensorSyncMeta  = reinterpret_cast<SensorSyncModeMetadata*>(pSyncMode);
            if (pSensorSyncMeta->isValid)
            {
                syncMode = pSensorSyncMeta->sensorSyncMode;
            }
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Get sensor sync meta failed");
        }
        pSlot->Unlock();
    }

    if (syncMode != m_currentSyncMode)
    {
        UINT dualCmdSize = 0;
        I2CRegSettingType i2cSettingType = I2CRegSettingType::Master;
        UINT regSettingIdx = 0;

        if (syncMode == MasterMode)
        {
            i2cSettingType = I2CRegSettingType::Master;
            dualCmdSize = GetSensorDataObject()->GetI2CCmdSize(I2CRegSettingType::Master, NULL, 0, &regSettingIdx);
        }
        else if (syncMode == SlaveMode)
        {
            i2cSettingType = I2CRegSettingType::Slave;
            dualCmdSize = GetSensorDataObject()->GetI2CCmdSize(I2CRegSettingType::Slave, NULL, 0, &regSettingIdx);
        }
        else if (syncMode == NoSync && m_currentSyncMode == SlaveMode)
        {
            i2cSettingType = I2CRegSettingType::Master;
            dualCmdSize = GetSensorDataObject()->GetI2CCmdSize(I2CRegSettingType::Master, NULL, 0, &regSettingIdx);
        }

        CAMX_LOG_INFO(CamxLogGroupSensor, "requestId: %llu, dualMode: %d,dualcmdSize:%d",
            requestId, syncMode, dualCmdSize);
        if (dualCmdSize != 0)
        {
            VOID* pDualUpdate = m_pUpdateCmds->BeginCommands(dualCmdSize / sizeof(UINT32));
            if (pDualUpdate != NULL)
            {
                result = GetSensorDataObject()->CreateI2CCmd(i2cSettingType, pDualUpdate, NULL, 0, regSettingIdx);
                if (CamxResultSuccess == result)
                {
                    result = m_pUpdateCmds->CommitCommands();
                    isNeedUpdateSyncMode = TRUE;
                }
            }
        }
    }

    if (((m_sensorParam.previousGain != m_sensorParam.currentGain) ||
         (m_sensorParam.previousLineCount != m_sensorParam.currentLineCount) ||
         (m_sensorParam.previousShortGain != m_sensorParam.currentShortGain) ||
         (m_sensorParam.previousFrameLengthLines != m_sensorParam.currentFrameLengthLines) ||
         (m_sensorParam.previousShortLineCount != m_sensorParam.currentShortLineCount)) &&
        (m_sensorParam.currentLineCount != 0))
    {
        UINT regSettingIdx = 0;
        UINT exposureUpdateCmdSize = GetSensorDataObject()->GetI2CCmdSize(I2CRegSettingType::AEC,
                                     m_pRegSettings, 0, &regSettingIdx);

        CAMX_LOG_VERBOSE(CamxLogGroupSensor, "requestId: %llu, exposureUpdateCmdSize: %d", requestId, exposureUpdateCmdSize);

        CAMX_ASSERT(0 != exposureUpdateCmdSize);
        CAMX_ASSERT(0 == (exposureUpdateCmdSize % sizeof(UINT32)));

        if (0 != exposureUpdateCmdSize)
        {
            VOID* pCmdBegin = m_pUpdateCmds->BeginCommands(exposureUpdateCmdSize / sizeof(UINT32));
            if (NULL != pCmdBegin)
            {
                CSLSensorI2CRandomWriteCmd* pCmdExpUpdate = reinterpret_cast<CSLSensorI2CRandomWriteCmd*>(pCmdBegin);

                result = GetSensorDataObject()->CreateI2CCmd(I2CRegSettingType::AEC, pCmdExpUpdate,
                                            m_pRegSettings, 0, regSettingIdx);
                if (CamxResultSuccess == result)
                {
                    result = m_pUpdateCmds->CommitCommands();
                    isNeedUpdateAEC = TRUE;
                }
            }
            else
            {
                result = CamxResultEFailed;
                CAMX_LOG_ERROR(CamxLogGroupSensor, "Failed to reserve exposure update command buffer");
            }
        }
    }

    if ((m_prevSensorPdafData.PDAFroiType != m_sensorPdafData.PDAFroiType) ||
        (m_prevSensorPdafData.PDAFstartX != m_sensorPdafData.PDAFstartX) ||
        (m_prevSensorPdafData.PDAFstartY != m_sensorPdafData.PDAFstartY) ||
        (m_prevSensorPdafData.PDAFendX != m_sensorPdafData.PDAFendX) ||
        (m_prevSensorPdafData.PDAFendY != m_sensorPdafData.PDAFendY) ||
        (m_prevSensorPdafData.horizontalWindowCount != m_sensorPdafData.horizontalWindowCount) ||
        (m_prevSensorPdafData.verticalWindowCount != m_sensorPdafData.verticalWindowCount))
    {
        CAMX_LOG_VERBOSE(CamxLogGroupSensor, "Prev [%d %d %d %d] Present [%d %d %d %d]",
                                            m_prevSensorPdafData.PDAFstartX,
                                            m_prevSensorPdafData.PDAFstartY,
                                            m_prevSensorPdafData.PDAFendX,
                                            m_prevSensorPdafData.PDAFendY,
                                            m_sensorPdafData.PDAFstartX,
                                            m_sensorPdafData.PDAFstartY,
                                            m_sensorPdafData.PDAFendX,
                                            m_sensorPdafData.PDAFendY);


        UINT regSettingIdx = 0;
        UINT pdafUpdateCmdSize = GetSensorDataObject()->GetI2CCmdSize(I2CRegSettingType::PDAF,
                                m_pPDAFSettings, 0, &regSettingIdx);

        CAMX_LOG_VERBOSE(CamxLogGroupSensor, "requestId: %llu, pdafUpdateCmdSize: %d", requestId, pdafUpdateCmdSize);

        CAMX_ASSERT(0 != pdafUpdateCmdSize);
        CAMX_ASSERT(0 == (pdafUpdateCmdSize % sizeof(UINT32)));

        if (0 != pdafUpdateCmdSize)
        {
            VOID* pCmdBegin = m_pUpdateCmds->BeginCommands(pdafUpdateCmdSize / sizeof(UINT32));
            if (NULL != pCmdBegin)
            {
                CSLSensorI2CRandomWriteCmd* pCmdPDAFUpdate = reinterpret_cast<CSLSensorI2CRandomWriteCmd*>(pCmdBegin);

                result = GetSensorDataObject()->CreateI2CCmd(I2CRegSettingType::PDAF,
                                  pCmdPDAFUpdate, m_pPDAFSettings, 0, regSettingIdx);

                if (CamxResultSuccess == result)
                {
                    result = m_pUpdateCmds->CommitCommands();
                    isNeedUpdatePDAF = TRUE;
                }
            }
            else
            {
                result = CamxResultEFailed;
                CAMX_LOG_ERROR(CamxLogGroupSensor, "Failed to reserve PDAF update command buffer");
            }
        }
    }

    if (CamxResultSuccess == result && (isNeedUpdateSyncMode || isNeedUpdateAEC || isNeedUpdatePDAF))
    {
        m_pUpdateCmds->SetRequestId(GetCSLSyncId(requestId));

        opcode = CSLPacketOpcodesSensorUpdate;
        if (FALSE == IsPipelineStreamedOn())
        {
            if (TRUE == m_initialConfigPending)
            {
                opcode                 = CSLPacketOpcodesSensorConfig;
                m_initialConfigPending = FALSE;
            }
        }
        else
        {
            m_initialConfigPending = TRUE;
        }

        m_pUpdatePacket->SetOpcode(CSLDeviceTypeInvalidDevice, opcode);

        result = m_pUpdatePacket->AddCmdBufferReference(m_pUpdateCmds, NULL);
    }
    else
    {
        CAMX_LOG_VERBOSE(CamxLogGroupSensor, "Sensor sending NOP packet");

        m_pUpdatePacket->SetOpcode(CSLDeviceTypeInvalidDevice, CSLPacketOpcodesNop);
        if (FALSE == IsPipelineStreamedOn())
        {
            if (TRUE == m_initialConfigPending)
            {
                m_initialConfigPending = FALSE;
            }
        }
    }

    if (CamxResultSuccess == result)
    {
        m_pUpdatePacket->SetRequestId(GetCSLSyncId(requestId));

        result = m_pUpdatePacket->CommitPacket();

        if (CamxResultSuccess == result)
        {
            result = m_pHwContext->Submit(m_hSensorDevice, m_pUpdatePacket);
        }
    }

    if (CamxResultSuccess == result)
    {
        m_currentSyncMode = syncMode;
        CAMX_LOG_VERBOSE(CamxLogGroupSensor, "Sensor per frame exposure update successful!");
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "Sensor per frame exposure update failed: %d", CamxResultStrings[result]);
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::GetCurrentFPS
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DOUBLE SensorNode::GetCurrentFPS()
{
    DOUBLE currentFPS       = GetSensorDataObject()->GetMaxFPS(m_currentResolutionIndex);
    UINT32 frameLengthLines = GetSensorDataObject()->GetFrameLengthLines(m_currentResolutionIndex);

    if (m_sensorParam.currentLineCount > frameLengthLines)
    {
        currentFPS = (currentFPS * frameLengthLines / m_sensorParam.currentLineCount);
    }

    CAMX_LOG_VERBOSE(CamxLogGroupSensor, "Configured current FPS = %lf", currentFPS);

    return currentFPS;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::GetFpsDiv
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DOUBLE SensorNode::GetFpsDiv()
{
    INT32  HALFpsRange[2] = { 0 };
    DOUBLE HALmaxFPS      = 0;
    DOUBLE fps_div        = 1.0;
    DOUBLE maxFPS         = static_cast<DOUBLE>(Utils::RoundDOUBLE(GetSensorDataObject()->GetMaxFPS(m_currentResolutionIndex)));
    UINT   HALInputfpsRangeData[] =
    {
        InputControlAETargetFpsRange
    };
    VOID* pData[1]       = { 0 };
    UINT64 pDataCount[1] = { 0 };

    GetDataList(HALInputfpsRangeData, pData, pDataCount, 1);

    if (NULL != pData[0])
    {
        Utils::Memcpy(&HALFpsRange, pData[0], sizeof(HALFpsRange));
    }
    HALmaxFPS = HALFpsRange[1];

    CAMX_LOG_VERBOSE(CamxLogGroupSensor, "HAL FPS min:max = %d:%d currentFPS = %lf", HALFpsRange[0], HALFpsRange[1], maxFPS);

    if (HALmaxFPS > maxFPS)
    {
        HALmaxFPS = maxFPS;
    }

    if (HALmaxFPS != 0)
    {
        fps_div = maxFPS / HALmaxFPS;
    }

    return fps_div;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::GetInitialCameraInfo
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::GetInitialCameraInfo(
    StatsCameraInfo* pCameraInfo)
{
    CamxResult result   = CamxResultSuccess;
    UINT cameraPosition = 0;

    pCameraInfo->cameraId = m_cameraId;
    result                = m_pSensorModuleData->GetCameraPosition(&cameraPosition);

    // Get initial camera information
    if (CamxResultSuccess == result && (TRUE == GetStaticSettings()->multiCameraEnable) &&
        (MultiCamera3ASyncDisabled != GetStaticSettings()->multiCamera3ASync))
    {
        // Convert CameraPosition to CHISENSORPOSITIONTYPE
        cameraPosition += 1;
        if (REAR == cameraPosition)
        {
            pCameraInfo->cameraType = StatsCameraTypeWide;
            pCameraInfo->algoRole   = StatsAlgoRoleMaster;
        }
        else if (REAR_AUX == cameraPosition)
        {
            pCameraInfo->cameraType = StatsCameraTypeTele;
            pCameraInfo->algoRole   = StatsAlgoRoleSlave;
        }
        else
        {
            pCameraInfo->cameraType = StatsCameraTypeDefault;
            pCameraInfo->algoRole   = StatsAlgoRoleDefault;
        }
    }
    else
    {
        pCameraInfo->cameraType = StatsCameraTypeDefault;
        pCameraInfo->algoRole   = StatsAlgoRoleDefault;
    }

    CAMX_LOG_VERBOSE(CamxLogGroupStats, "Sensor initial camera info: ID:%d type:%d role:%d",
        pCameraInfo->cameraId,
        pCameraInfo->cameraType,
        pCameraInfo->algoRole);

    return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::AcquireDevice
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::AcquireDevice()
{
    CAMX_ENTRYEXIT_SCOPE(CamxLogGroupSensor, SCOPEEventSensorAcquire);

    CamxResult  result             = CamxResultEFailed;
    SubDeviceProperty sensorDevice = m_pSensorSubDevicesCache->GetSubDevice(m_cameraId, SensorHandle);
    SubDeviceProperty csiphyDevice = m_pSensorSubDevicesCache->GetSubDevice(m_cameraId, CSIPHYHandle);

    CAMX_LOG_INFO(CamxLogGroupSensor, "m_sensorDeviceIndex:%d, m_CSIPHYDeviceIndex: %d",
                                       sensorDevice.deviceIndex, csiphyDevice.deviceIndex);

    if (FALSE == sensorDevice.isAcquired)
    {
        CAMX_LOG_INFO(CamxLogGroupSensor, "Acquiring sensor device handle");

        result = CSLAcquireDevice(m_pHwContext->GetCSLSession(),
                                  &m_hSensorDevice,
                                  sensorDevice.deviceIndex,
                                  NULL,
                                  0,
                                  NULL,
                                  0,
                                  NameAndInstanceId());
        CAMX_LOG_INFO(CamxLogGroupSensor, "Acquired sensor device handle: %p for camerId: %d",
                                           m_hSensorDevice, m_cameraId);
        m_pSensorSubDevicesCache->SetSubDeviceHandle(m_cameraId, m_hSensorDevice, SensorHandle);
    }
    else
    {
        CAMX_ASSERT(sensorDevice.hDevice != CSLInvalidHandle);
        m_hSensorDevice = sensorDevice.hDevice;
        CAMX_LOG_INFO(CamxLogGroupSensor, "Reusing sensor device handle: %p for camerId: %d",
                                           m_hSensorDevice, m_cameraId);
        m_sensorConfigStatus = SensorConfigurationStatus::SensorInitializationComplete;
        result = CamxResultSuccess;
    }


    if (CamxResultSuccess == result)
    {
        SetDeviceAcquired(TRUE);
        AddCSLDeviceHandle(m_hSensorDevice);
        CAMX_LOG_INFO(CamxLogGroupSensor, "AcquireDevice on Sensor successful!");
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor, "AcquireDevice on Sensor failed: %d", CamxResultStrings[result]);
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::IsStatsNodeEnabled
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL SensorNode::IsStatsNodeEnabled()
{
    BOOL isEnabled = TRUE;
    const StaticSettings* pStaticSettings = GetStaticSettings();

    if ( (FALSE == GetPipeline()->HasStatsNode()) || (TRUE == pStaticSettings->disableStatsNode) )
    {
        isEnabled = FALSE;
    }

    return isEnabled;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SensorNode::SensorThreadJobCallback
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID* SensorNode::SensorThreadJobCallback(
    VOID* pData)
{
    CamxResult  result            = CamxResultEFailed;
    SensorPostJob* pSensorPostJob = reinterpret_cast<SensorPostJob*>(pData);

    if ((NULL != pSensorPostJob) && (NULL != pSensorPostJob->pSensor))
    {
        SensorNode* pSensorNode          = static_cast<SensorNode*>(pSensorPostJob->pSensor);
        SensorPostJobCommand condition   = pSensorPostJob->sensorJobCommand;

        switch (condition)
        {
            case SensorPostJobCommand::InitializeSensor:
                {
                    pSensorNode->m_signalSensorInit.pMutex->Lock();
                    result = pSensorNode->LoadSensorInitConfigCmd();
                    pSensorNode->m_signalSensorInit.pWaitCondition->Broadcast();
                    pSensorNode->m_signalSensorInit.pMutex->Unlock();

                    if (pSensorPostJob != NULL)
                    {
                        CAMX_DELETE(pSensorPostJob);
                        pSensorPostJob = NULL;
                    }

                    break;
                }
            case SensorPostJobCommand::ConfigureSensor:
                {
                    pSensorNode->m_signalSensorInit.pMutex->Lock();
                    if ((SensorConfigurationStatus::SensorInitializationFailed != pSensorNode->m_sensorConfigStatus) &&
                        (SensorConfigurationStatus::SensorInitializationComplete != pSensorNode->m_sensorConfigStatus))
                    {
                        pSensorNode->m_signalSensorInit.pWaitCondition->Wait(
                            pSensorNode->m_signalSensorInit.pMutex->GetNativeHandle());
                    }
                    pSensorNode->m_signalSensorInit.pMutex->Unlock();

                    pSensorNode->m_signalSensorConfig.pMutex->Lock();
                    result = pSensorNode->LoadSensorConfigCmds();
                    pSensorNode->m_signalSensorConfig.pWaitCondition->Broadcast();
                    pSensorNode->m_signalSensorConfig.pMutex->Unlock();

                    if (pSensorPostJob != NULL)
                    {
                        CAMX_DELETE(pSensorPostJob);
                        pSensorPostJob = NULL;
                    }

                    break;
                }
            case SensorPostJobCommand::SubModulesCreate:
                {
                    pSensorNode->m_signalSensorConfig.pMutex->Lock();
                    if ((SensorConfigurationStatus::SensorConfigurationComplete != pSensorNode->m_sensorConfigStatus) &&
                        (SensorConfigurationStatus::SensorConfigurationFailed != pSensorNode->m_sensorConfigStatus))
                    {
                        pSensorNode->m_signalSensorConfig.pWaitCondition->Wait(
                            pSensorNode->m_signalSensorConfig.pMutex->GetNativeHandle());
                    }
                    pSensorNode->m_signalSensorConfig.pMutex->Unlock();

                    pSensorNode->m_signalSensorSubModules.pMutex->Lock();
                    result = pSensorNode->CreateSensorSubmodules();
                    pSensorNode->m_signalSensorSubModules.pWaitCondition->Broadcast();
                    pSensorNode->m_signalSensorSubModules.pMutex->Unlock();

                    if (pSensorPostJob != NULL)
                    {
                        CAMX_DELETE(pSensorPostJob);
                        pSensorPostJob = NULL;
                    }

                    break;
                }
            case SensorPostJobCommand::InitializeOIS:
                {
                    pSensorNode->m_signalOISInit.pMutex->Lock();
                    result = pSensorNode->CreateOISSubmodule();
                    pSensorNode->m_signalOISInit.pWaitCondition->Broadcast();
                    pSensorNode->m_signalOISInit.pMutex->Unlock();

                    if (pSensorPostJob != NULL)
                    {
                        CAMX_DELETE(pSensorPostJob);
                        pSensorPostJob = NULL;
                    }

                    break;
                }
            default:
                {
                    result = CamxResultEFailed;
                    CAMX_LOG_ERROR(CamxLogGroupSensor, "Sensor CB execution failed");
                    break;
                }
        }

        if (CamxResultSuccess != result)
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Sensor workerCore failed with result %s", CamxResultStrings[result]);
        }
    }

    return NULL;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::LoadSensorInitConfigCmd
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::LoadSensorInitConfigCmd()
{
    CamxResult  result = CamxResultSuccess;

    if (SensorConfigurationStatus::SensorConfigurationStateUninitialized == m_sensorConfigStatus)
    {
        m_sensorConfigStatus = SensorConfigurationStatus::SensorInitializationInProgress;
        UINT initializeCmdSize = 0;
        UINT WBCmdSize = 0;
        UINT LSCCmdSize = 0;
        UINT regSettingIdx = 0;
        do
        {
            UINT curRegSettingIdx = regSettingIdx;
            // NOWHINE NC011: Asking for exception, sensor commands are well known as - init, res, AEC, start, stop etc
            initializeCmdSize = GetSensorDataObject()->GetI2CCmdSize(I2CRegSettingType::Init,
            NULL, 0, &regSettingIdx);

            // All sizes should be a multiple of dword
            CAMX_ASSERT(0 == (initializeCmdSize % sizeof(UINT32)));

            CAMX_LOG_INFO(CamxLogGroupSensor, "Sensor initializeCmdSize: %d", initializeCmdSize);

            // NOWHINE NC011: Asking for exception, sensor commands are well known as - init
            result = CreateAndSubmitCommand(initializeCmdSize, I2CRegSettingType::Init,
                CSLPacketOpcodesSensorInitialConfig, 0, curRegSettingIdx);

            if (CamxResultSuccess == result)
            {
                if ((NULL != m_pOTPData) &&
                    (0 != m_pOTPData->WBCalibration[0].settings.regSettingCount))
                {
                    WBCmdSize = GetSensorDataObject()->GetI2CCmdSize(
                        I2CRegSettingType::AWB,
                        static_cast<const VOID*>(&m_pOTPData->WBCalibration[0].settings),
                        0,
                        &regSettingIdx);

                    if (0 != WBCmdSize)
                    {
                        CAMX_LOG_INFO(CamxLogGroupSensor, "Sensor WBCmdSize: %d", WBCmdSize);
                        CAMX_ASSERT(0 == (WBCmdSize % sizeof(UINT32)));
                        result = CreateAndSubmitCommand(WBCmdSize,
                                                        I2CRegSettingType::AWB,
                                                        CSLPacketOpcodesSensorInitialConfig,
                                                        0,
                                                        curRegSettingIdx);
                        if (CamxResultSuccess == result)
                        {
                            CAMX_LOG_VERBOSE(CamxLogGroupSensor, "AWBSetting initialized successful!");
                        }
                        else
                        {
                            CAMX_LOG_ERROR(CamxLogGroupSensor, "AWBSetting initialized failed!");
                        }
                    }
                }
                if (CamxResultSuccess == result)
                {
                    if ((NULL != m_pOTPData) &&
                        (0 != m_pOTPData->LSCCalibration[0].settings.regSettingCount))
                    {
                        LSCCmdSize = GetSensorDataObject()->GetI2CCmdSize(
                            I2CRegSettingType::LSC,
                            static_cast<const VOID*>(&m_pOTPData->LSCCalibration[0].settings),
                            0,
                            &regSettingIdx);

                        if (0 != LSCCmdSize)
                        {
                            CAMX_LOG_INFO(CamxLogGroupSensor, "Sensor lSCCmdSize: %d", LSCCmdSize);
                            CAMX_ASSERT(0 == (LSCCmdSize % sizeof(UINT32)));
                            result = CreateAndSubmitCommand(LSCCmdSize,
                                                            I2CRegSettingType::LSC,
                                                            CSLPacketOpcodesSensorInitialConfig,
                                                            0,
                                                            curRegSettingIdx);
                            if (CamxResultSuccess == result)
                            {
                                CAMX_LOG_VERBOSE(CamxLogGroupSensor, "LSCSetting initialized successful!");
                            }
                            else
                            {
                                CAMX_LOG_ERROR(CamxLogGroupSensor, "LSCSetting initialized failed!");
                            }
                        }
                    }
                }
                m_sensorConfigStatus = SensorConfigurationStatus::SensorInitializationComplete;
                CAMX_LOG_INFO(CamxLogGroupSensor, "Sensor initialized successfully");
            }
            else
            {
                m_sensorConfigStatus = SensorConfigurationStatus::SensorInitializationFailed;
                CAMX_LOG_ERROR(CamxLogGroupSensor, "Sensor initialization failed");
            }
        } while (regSettingIdx != 0);
    }
    else
    {
        CAMX_LOG_INFO(CamxLogGroupSensor, "Sensor initialization sequence already done");
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::GetSensorModuleIndexes
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::GetSensorModuleIndexes(
    CSLCSIPHYCapability*     pCSIPHYCapability,
    CSLFlashQueryCapability* pFlashCapability,
    CSLActuatorCapability*   pActuatorCap,
    CSLOISCapability*        pOisCap)
{
    CDKResult result = CDKResultEFailed;
    // Get the slot info for this camera
    CSLSensorCapability sensorCap    = { 0 };
    SubDeviceProperty sensorDevice   = m_pSensorSubDevicesCache->GetSubDevice(m_cameraId, SensorHandle);
    SubDeviceProperty CSIPHYDevice   = m_pSensorSubDevicesCache->GetSubDevice(m_cameraId, CSIPHYHandle);
    SubDeviceProperty OISDevice      = m_pSensorSubDevicesCache->GetSubDevice(m_cameraId, OISHandle);
    SubDeviceProperty actuatorDevice = m_pSensorSubDevicesCache->GetSubDevice(m_cameraId, ActuatorHandle);
    SubDeviceProperty flashDevice    = m_pSensorSubDevicesCache->GetSubDevice(m_cameraId, FlashHandle);


    INT32 deviceIndices[MaxNumImageSensors] = { 0 };
    UINT  actualNumIndices = 0;

    if (FALSE == sensorDevice.isAcquired)
    {
        /// @todo (CAMX-555) Add a function in HwContext to get the camera device indices for this session
        result = HwEnvironment::GetInstance()->GetDeviceIndices(CSLDeviceTypeImageSensor,
                                                                &deviceIndices[0],
                                                                MaxNumImageSensors,
                                                                &actualNumIndices);

        if (CamxResultSuccess == result)
        {
            CAMX_ASSERT(m_cameraId < actualNumIndices);
            m_pSensorSubDevicesCache->SetSubDeviceIndex(m_cameraId, deviceIndices[m_cameraId], SensorHandle);
            sensorDevice = m_pSensorSubDevicesCache->GetSubDevice(m_cameraId, SensorHandle); // to get the updated value
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Failed to get device index for Sensor");
            return result;
        }
    }

    if (CamxResultSuccess == AddDeviceIndex(sensorDevice.deviceIndex))
    {

        result = CSLQueryDeviceCapabilities(sensorDevice.deviceIndex,
                                            &sensorCap,
                                            sizeof(CSLSensorCapability));

        if (CamxResultSuccess == result)
        {
            CAMX_LOG_VERBOSE(CamxLogGroupSensor,
                "SensorDeviceIndex[%d] Cap={slotInfo:%d,CSIPHY:%d,actuator:%d,EEPROM:%d,flash:%d OIS:%d}",
                sensorDevice.deviceIndex,
                sensorCap.slotInfo,
                sensorCap.CSIPHYSlotId,
                sensorCap.actuatorSlotId,
                sensorCap.EEPROMSlotId,
                sensorCap.flashSlotId,
                sensorCap.OISSlotId);
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Failed to query sensor capabilites");
            return result;
        }
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor,
            "Failed to add device result: %d, sensor index: %d, actual indices: %d",
            CamxResultStrings[result],
            sensorDevice.deviceIndex,
            actualNumIndices);

        return result;
    }

    if (FALSE == CSIPHYDevice.isAcquired)
    {
        result = HwEnvironment::GetInstance()->GetDeviceIndices(CSLDeviceTypeCSIPHY,
                                                                &deviceIndices[0],
                                                                MaxNumImageSensors,
                                                                &actualNumIndices);

        if (CamxResultSuccess == result)
        {
            // Find CSIPHY index match sensor slot info
            for (UINT i = 0; i < actualNumIndices; i++)
            {
                if ((CamxResultSuccess == CSLQueryDeviceCapabilities(deviceIndices[i],
                                                                     pCSIPHYCapability,
                                                                     sizeof(CSLCSIPHYCapability))) &&
                    (pCSIPHYCapability->slotInfo == sensorCap.CSIPHYSlotId))
                {
                    CAMX_LOG_VERBOSE(CamxLogGroupSensor,
                        "Found matched CSIPHY[%d] deviceIndices %d slotInfo %d",
                        i,
                        deviceIndices[i],
                        pCSIPHYCapability->slotInfo);

                    m_pSensorSubDevicesCache->SetSubDeviceIndex(m_cameraId, deviceIndices[i], CSIPHYHandle);
                    CSIPHYDevice = m_pSensorSubDevicesCache->GetSubDevice(m_cameraId, CSIPHYHandle); // to get the updated value
                    break;
                }
            }
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Failed to get device indices for CSIPHY");
            return result;
        }
    }
    else
    {
        if ((CamxResultSuccess != CSLQueryDeviceCapabilities(CSIPHYDevice.deviceIndex,
                                                             pCSIPHYCapability,
                                                             sizeof(CSLCSIPHYCapability))) ||
            (pCSIPHYCapability->slotInfo != sensorCap.CSIPHYSlotId))
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Cached CSIPHY device index: %d is not valid for given sensor",
                CSIPHYDevice.deviceIndex);
            return CamxResultEFailed;
        }
    }

    result = AddDeviceIndex(CSIPHYDevice.deviceIndex);

    if (CamxResultSuccess != result)
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor,
            "Failed to add device result: %d, CSIPHY index: %d, actual indices: %d",
            CamxResultStrings[result],
            CSIPHYDevice.deviceIndex,
            actualNumIndices);

        return result;
    }

    if (FALSE == actuatorDevice.isAcquired)
    {
        result = HwEnvironment::GetInstance()->GetDeviceIndices(CSLDeviceTypeLensActuator,
                                                                &deviceIndices[0],
                                                                MaxNumImageSensors,
                                                                &actualNumIndices);
        if (CamxResultSuccess == result)
        {
            // Find Actuator index match sensor slot info
            for (UINT i = 0; i < actualNumIndices; i++)
            {
                if ((CamxResultSuccess == CSLQueryDeviceCapabilities(deviceIndices[i],
                                                                     pActuatorCap,
                                                                     sizeof(CSLActuatorCapability))) &&
                    (pActuatorCap->slotInfo == sensorCap.actuatorSlotId))
                {
                    CAMX_LOG_INFO(CamxLogGroupSensor,
                        "Found matched Actautor[%d] deviceIndices %d slotInfo %d",
                        i,
                        deviceIndices[i],
                        pActuatorCap->slotInfo);

                    m_pSensorSubDevicesCache->SetSubDeviceIndex(m_cameraId, deviceIndices[i], ActuatorHandle);
                    // To get the updated value
                    actuatorDevice = m_pSensorSubDevicesCache->GetSubDevice(m_cameraId, ActuatorHandle);
                    break;
                }
            }
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Failed to get device indices for actuator");
        }
    }
    else
    {
        if ((CamxResultSuccess != CSLQueryDeviceCapabilities(actuatorDevice.deviceIndex,
                                                             pActuatorCap,
                                                             sizeof(CSLActuatorCapability))) ||
            (pActuatorCap->slotInfo != sensorCap.actuatorSlotId))
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Cached actuator device index: %d is not valid for given sensor",
                actuatorDevice.deviceIndex);
        }
    }

    if (CamxResultSuccess == result)
    {
        result = AddDeviceIndex(actuatorDevice.deviceIndex);
    }

    if (CamxResultSuccess != result)
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor,
            "Failed to add device result: %d, actuator index: %d, actual indices: %d",
            CamxResultStrings[result],
            actuatorDevice.deviceIndex,
            actualNumIndices);
    }

    if (FALSE == OISDevice.isAcquired)
    {
        result = HwEnvironment::GetInstance()->GetDeviceIndices(CSLDeviceTypeOIS,
                                                                &deviceIndices[0],
                                                                MaxNumImageSensors,
                                                                &actualNumIndices);
        if (CamxResultSuccess == result)
        {
            // Find Ois index match sensor slot info
            for (UINT i = 0; i < actualNumIndices; i++)
            {
                if ((CamxResultSuccess == CSLQueryDeviceCapabilities(deviceIndices[i],
                    pOisCap,
                    sizeof(CSLOISCapability))) &&
                    (pOisCap->slotInfo == sensorCap.OISSlotId))
                {
                    CAMX_LOG_INFO(CamxLogGroupSensor,
                        "Found matched OIS[%d] deviceIndices %d slotInfo %d",
                        i,
                        deviceIndices[i],
                        pOisCap->slotInfo);

                    m_pSensorSubDevicesCache->SetSubDeviceIndex(m_cameraId, deviceIndices[i], OISHandle);
                    OISDevice = m_pSensorSubDevicesCache->GetSubDevice(m_cameraId, OISHandle); // to get the updated value
                }
            }
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Failed to get device indices for OIS");
        }
    }
    else
    {
        if ((CamxResultSuccess != CSLQueryDeviceCapabilities(OISDevice.deviceIndex,
                                                             pOisCap,
                                                             sizeof(CSLOISCapability))) &&
            (pOisCap->slotInfo != sensorCap.OISSlotId))
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Cached OIS device index: %d is not valid for given sensor",
                OISDevice.deviceIndex);
        }
    }

    if (CamxResultSuccess == result)
    {
        result = AddDeviceIndex(OISDevice.deviceIndex);
    }

    if (CamxResultSuccess != result)
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor,
            "Failed to add device result: %d, ois index: %d, actual indices: %d",
            CamxResultStrings[result],
            OISDevice.deviceIndex,
            actualNumIndices);
    }

    if (FALSE == flashDevice.isAcquired)
    {
        // Query capability for flash device
        result = HwEnvironment::GetInstance()->GetDeviceIndices(CSLDeviceTypeFlash,
                                                                &deviceIndices[0],
                                                                MaxNumImageSensors,
                                                                &actualNumIndices);

        if ((CamxResultSuccess == result) && (actualNumIndices > 0))
        {
            // Find flash index match sensor slot info
            for (UINT i = 0; i < actualNumIndices; i++)
            {
                if (CamxResultSuccess == CSLQueryDeviceCapabilities(deviceIndices[i],
                                                                    pFlashCapability,
                                                                    sizeof(CSLFlashQueryCapability)))
                {
                    CAMX_LOG_VERBOSE(CamxLogGroupSensor,
                        "Index %d deviceIndices %d flash slotInfo %d sensorCap SlotInfo %d",
                        i,
                        deviceIndices[i],
                        pFlashCapability->slotInfo,
                        sensorCap.slotInfo);

                    for (UINT j = 0; j < CSLFlashMaxLEDTrigger; j++)
                    {
                        CAMX_LOG_VERBOSE(CamxLogGroupSensor,
                            "Flash %d maxCurrent %d maxDuration %d maxTorchCurrent %d",
                            pFlashCapability->maxFlashCurrent[j],
                            pFlashCapability->maxFlashDuration[j],
                            pFlashCapability->maxTorchCurrent[j])
                    }

                    if (pFlashCapability->slotInfo == sensorCap.flashSlotId)
                    {
                        m_pSensorSubDevicesCache->SetSubDeviceIndex(m_cameraId, deviceIndices[i], FlashHandle);
                        // To get the updated value
                        flashDevice = m_pSensorSubDevicesCache->GetSubDevice(m_cameraId, FlashHandle);
                        break;
                    }
                }
            }
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "GetDeviceIndex failure for Flash, no flash hardware found");
        }
    }
    else
    {
        if ((CamxResultSuccess != CSLQueryDeviceCapabilities(flashDevice.deviceIndex,
                                                             pFlashCapability,
                                                             sizeof(CSLFlashQueryCapability))) ||
            (pFlashCapability->slotInfo != sensorCap.flashSlotId))
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Cached flash device index: %d is not valid for given sensor",
                flashDevice.deviceIndex);
        }
    }

    if (CamxResultSuccess == result)
    {
        result = AddDeviceIndex(flashDevice.deviceIndex);
    }


    if (CamxResultSuccess != result)
    {
        CAMX_LOG_ERROR(CamxLogGroupSensor,
            "Failed to add device result: %d, flash index: %d, actual indices: %d",
            CamxResultStrings[result],
            flashDevice.deviceIndex,
            actualNumIndices);
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::CreateSensorSubmodules
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::CreateSensorSubmodules()
{
    CamxResult      result = CamxResultSuccess;
    StatsCameraInfo cameraInfo;

    CAMX_ENTRYEXIT_SCOPE(CamxLogGroupSensor, SCOPEEventSubModuleAcquire);

    if (SensorConfigurationStatus::SensorConfigurationComplete == m_sensorConfigStatus)
    {
        m_sensorConfigStatus = SensorConfigurationStatus::SensorSubModuleCreateInProgress;

        result = CreateSubModules();

        if (CamxResultSuccess == result)
        {
            result = CreatePerFrameUpdateResources();
        }
        if (CamxResultSuccess == result)
        {
            result = GetInitialCameraInfo(&cameraInfo);
        }

        if ((CamxResultSuccess == result) && (NULL != m_pSensorModuleData->GetActuatorDataObject()))
        {
            ActuatorCreateData createData = {0};

            createData.pHwContext            = m_pHwContext;
            createData.pMainPool             = GetPerFramePool(PoolType::PerFrameResult);
            createData.pPerUsecasePool       = GetPerFramePool(PoolType::PerUsecase);
            createData.pInitPacketManager    = m_pActuatorInitializePacketManager;
            createData.pInitCmdManager       = m_pActuatorInitializeCmdManager;
            createData.pI2CInfoCmdManager    = m_pActuatorI2CInfoCmdManager;
            createData.pPowerCmdManager      = m_pActuatorPowerCmdManager;
            createData.cameraId              = m_cameraId;
            createData.pParentNode           = this;
            createData.pOTPData              = m_pOTPData;
            createData.requestQueueDepth     = GetPipeline()->GetRequestQueueDepth();
            SubDeviceProperty actuatorDevice = m_pSensorSubDevicesCache->GetSubDevice(m_cameraId, ActuatorHandle);

            result = Actuator::Create(&createData, actuatorDevice.deviceIndex);

            if (CamxResultSuccess == result)
            {
                m_pActuator = createData.pActuator;
            }
            /// @todo (CAMX-555) publish property to 3A regarding sensitivity and if actuator is supported
        }

        if ((CamxResultSuccess == result)               &&
            (FALSE == GetStaticSettings()->disablePDAF) &&
            (TRUE == m_isPDAFEnabled))
        {
            // No Need to check for failed PDAF init since this is an optional feature
            PDAFData* pPDAFData = m_pSensorModuleData->GetPDAFDataObj();
            VOID* pTuningManager = GetTuningDataManager()->GetChromatix();

            PDLibDataBufferInfo CAMIFT3DataPattern;
            Utils::Memset(&CAMIFT3DataPattern, 0, sizeof(PDLibDataBufferInfo));
            GetPDAFT3CAMIFPattern(&CAMIFT3DataPattern, pPDAFData);
            pPDAFData->PDAFInit(m_pPDLib,
                m_currentResolutionIndex,
                m_pSensorModuleData->GetActuatorDataObject(),
                m_pSensorModuleData->GetSensorDataObject(),
                m_pOTPData,
                &cameraInfo,
                pTuningManager,
                &CAMIFT3DataPattern);
        }

        if (CamxResultSuccess == result)
        {
            const CSIInformation*   pCSIInfo        = m_pSensorModuleData->GetCSIInfo();
            CSLSensorCSIPHYInfo     cmdCSIPHYConfig = {0};
            if (NULL != pCSIInfo)
            {
                GetSensorDataObject()->CreateCSIPHYConfig(&cmdCSIPHYConfig, pCSIInfo->laneAssign, pCSIInfo->isComboMode);
                cmdCSIPHYConfig.secureMode = static_cast<UINT8>(IsSecureMode());
                result                     = m_pCSIPHY->Configure(&cmdCSIPHYConfig);
                if (CamxResultSuccess != result)
                {
                    CAMX_LOG_ERROR(CamxLogGroupSensor, "CSI Configuration failed");
                }
            }
        }

        if (CamxResultSuccess == result)
        {
            PublishLensInformation();
            PublishCameraModuleInformation();
            PublishISO100GainInformation();

            m_sensorConfigStatus = SensorConfigurationStatus::SensorSubModuleCreateComplete;
            CAMX_LOG_INFO(CamxLogGroupSensor, "Sensor Submodule creation successful");
        }
        else
        {
            m_sensorConfigStatus = SensorConfigurationStatus::SensorSubModuleCreateFailed;
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Sensor Submodule creation failed");
        }
    }
    else
    {
        result = CamxResultEFailed;
        m_sensorConfigStatus = SensorConfigurationStatus::SensorSubModuleCreateFailed;
        CAMX_LOG_ERROR(CamxLogGroupSensor, "Creating sensor submodules failed due to failed sensor configuration");
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::CreateOISSubmodule
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::CreateOISSubmodule()
{
    CamxResult      result = CamxResultSuccess;

    if (SensorOISConfigurationStatus::SensorOISConfigurationStateUninitialized == m_OISConfigStatus)
    {
        m_OISConfigStatus = SensorOISConfigurationStatus::SensorOISInitializationInProgress;

        result = CreatePerFrameUpdateOISResources();

        if (CamxResultSuccess == result)
        {
            m_OISConfigStatus = SensorOISConfigurationStatus::SensorOISInitializationComplete;
            CAMX_LOG_INFO(CamxLogGroupSensor, "OIS Submodule creation successful");
        }
        else
        {
            m_OISConfigStatus = SensorOISConfigurationStatus::SensorOISInitializationFailed;
            CAMX_LOG_ERROR(CamxLogGroupSensor, "OIS submodule creation failed");
        }
    }
    else
    {
        result = CamxResultEFailed;
        m_OISConfigStatus = SensorOISConfigurationStatus::SensorOISInitializationFailed;
        CAMX_LOG_ERROR(CamxLogGroupSensor, "OIS submodule creation failed");
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::CreatePerFrameUpdateOISResources
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::CreatePerFrameUpdateOISResources()
{
    CamxResult result = CamxResultSuccess;

    if (NULL != m_pSensorModuleData->GetOisDataObject())
    {
        CAMX_TRACE_SYNC_BEGIN_F(CamxLogGroupSensor, "CreateOisResources");
        result = CreateOisResources();
        CAMX_TRACE_SYNC_END(CamxLogGroupSensor);
        if (CamxResultSuccess != result)
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "OIS creation failed");
        }
    }
    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SensorNode::GetPDAFT3CAMIFPattern
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult SensorNode::GetPDAFT3CAMIFPattern(
    PDLibDataBufferInfo* pCAMIFT3DataPattern,
    PDAFData* pPDAFData)
{
    PDLibDataBufferInfo*         pInputDataPatternFromIFE = NULL;
    const PDAFConfigurationData* pPDAFConfigData          = NULL;
    CamxResult                   result                   = CamxResultSuccess;
    PDAFType                     PDType                   = PDAFType::PDTypeUnknown;

    if (NULL != pPDAFData)
    {
        pPDAFConfigData = pPDAFData->GetPDAFConfigData();
        if (NULL != pPDAFConfigData)
        {
            PDType = pPDAFConfigData->PDInfo.PDType;
        }
    }

    if (PDAFType::PDType3 == PDType)
    {
        static const UINT T3DataPattern[] =
        {
            PropertyIDUsecaseIFEPDAFInfo
        };
        VOID*  pT3dataPattern[1]        = { 0 };
        UINT   length                   = CAMX_ARRAY_SIZE(T3DataPattern);
        UINT64 propertyDataOffset[1]    = { 0 };
        GetDataList(T3DataPattern, pT3dataPattern, propertyDataOffset, length);
        pInputDataPatternFromIFE  = reinterpret_cast<PDLibDataBufferInfo*>(pT3dataPattern[0]);

        if ((NULL != pInputDataPatternFromIFE) && (NULL != pCAMIFT3DataPattern))
        {
            pCAMIFT3DataPattern->bufferFormat = pInputDataPatternFromIFE->bufferFormat;
            pCAMIFT3DataPattern->imageOverlap = pInputDataPatternFromIFE->imageOverlap;
            pCAMIFT3DataPattern->isp1BufferStride = pInputDataPatternFromIFE->isp1BufferStride;
            pCAMIFT3DataPattern->isp1BufferWidth = pInputDataPatternFromIFE->isp1BufferWidth;
            pCAMIFT3DataPattern->isp2BufferStride = pInputDataPatternFromIFE->isp2BufferStride;
            pCAMIFT3DataPattern->isp2BufferWidth = pInputDataPatternFromIFE->isp2BufferWidth;
            pCAMIFT3DataPattern->isp2ImageOffset = pInputDataPatternFromIFE->isp2ImageOffset;
            pCAMIFT3DataPattern->ispBufferHeight = pInputDataPatternFromIFE->ispBufferHeight;
            pCAMIFT3DataPattern->sensorType = pInputDataPatternFromIFE->sensorType;

            pCAMIFT3DataPattern->isp1BlockPattern.pixelCount =
                pInputDataPatternFromIFE->isp1BlockPattern.pixelCount;
            pCAMIFT3DataPattern->isp1BlockPattern.verticalPDOffset =
                pInputDataPatternFromIFE->isp1BlockPattern.verticalPDOffset;
            pCAMIFT3DataPattern->isp1BlockPattern.horizontalPDOffset =
                pInputDataPatternFromIFE->isp1BlockPattern.horizontalPDOffset;
            pCAMIFT3DataPattern->isp1BlockPattern.blockDimension.width =
                pInputDataPatternFromIFE->isp1BlockPattern.blockDimension.width;
            pCAMIFT3DataPattern->isp1BlockPattern.blockDimension.height =
                pInputDataPatternFromIFE->isp1BlockPattern.blockDimension.height;
            for (UINT index = 0; index < pCAMIFT3DataPattern->isp1BlockPattern.pixelCount; index++)
            {
                pCAMIFT3DataPattern->isp1BlockPattern.pixelCoordinate[index].x =
                    pInputDataPatternFromIFE->isp1BlockPattern.pixelCoordinate[index].x;

                pCAMIFT3DataPattern->isp1BlockPattern.pixelCoordinate[index].y =
                    pInputDataPatternFromIFE->isp1BlockPattern.pixelCoordinate[index].y;

                pCAMIFT3DataPattern->isp1BlockPattern.pixelCoordinate[index].type =
                    pInputDataPatternFromIFE->isp1BlockPattern.pixelCoordinate[index].type;
            }

            pCAMIFT3DataPattern->isp2BlockPattern.pixelCount =
                pInputDataPatternFromIFE->isp2BlockPattern.pixelCount;
            pCAMIFT3DataPattern->isp2BlockPattern.verticalPDOffset =
                pInputDataPatternFromIFE->isp2BlockPattern.verticalPDOffset;
            pCAMIFT3DataPattern->isp2BlockPattern.horizontalPDOffset =
                pInputDataPatternFromIFE->isp2BlockPattern.horizontalPDOffset;
            pCAMIFT3DataPattern->isp2BlockPattern.blockDimension.width =
                pInputDataPatternFromIFE->isp2BlockPattern.blockDimension.width;
            pCAMIFT3DataPattern->isp2BlockPattern.blockDimension.height =
                pInputDataPatternFromIFE->isp2BlockPattern.blockDimension.height;
            for (UINT index = 0; index < pCAMIFT3DataPattern->isp2BlockPattern.pixelCount; index++)
            {
                pCAMIFT3DataPattern->isp2BlockPattern.pixelCoordinate[index].x =
                    pInputDataPatternFromIFE->isp2BlockPattern.pixelCoordinate[index].x;

                pCAMIFT3DataPattern->isp2BlockPattern.pixelCoordinate[index].y =
                    pInputDataPatternFromIFE->isp2BlockPattern.pixelCoordinate[index].y;

                pCAMIFT3DataPattern->isp2BlockPattern.pixelCoordinate[index].type =
                    pInputDataPatternFromIFE->isp2BlockPattern.pixelCoordinate[index].type;
            }
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupSensor, "Cannot get IFE CAMIF T3 Extracted pattern");
            result = CamxResultEFailed;
        }
    }

    return result;
}


CAMX_NAMESPACE_END
